feat: export core Hermes skills

This commit is contained in:
2026-07-15 02:45:56 +00:00
parent a028b63eda
commit 54711fee2a
308 changed files with 41310 additions and 1 deletions
+160
View File
@@ -0,0 +1,160 @@
---
name: legal-document-review
description: 法律文书审核——对已成稿的法律文书(管辖权异议、答辩状、起诉状、合同、法律意见等)做质量审核。Maggie/莎莎说"审核""审阅""帮我看看这份文件有没有问题"时按此标准走。六维度检查(内容疏漏、逻辑错误、表达不准确、错别字、格式、段落),发现问题先提示再用修订模式(tracked changes)修改。区别于文书"制作"(litigation-document-preparation)和"咨询答疑"(legal-research-and-advisory)——本skill针对的是审核他人已写好的稿件。
---
# 法律文书审核(Legal Document Review)
## 触发条件
Maggie或团队律师(莎莎、Doro、刘婷等)发来一份**已成稿**的法律文书,要求"审核/审阅/帮我看看有没有问题"。
不是从头制作(那是 litigation-document-preparation),也不是回答法律问题(那是 legal-research-and-advisory)。
## 跨session项目连续性(2026-07-11教训)
涉及进行中的法律项目(苏州新东方、万禹案等)时,开新对话**第一步必须session_search回顾上次确认的事实和结论**(主体性质、经营范围、核心法律定性等),不要从零开始重新检索已确认的事实。被用户问"你不记得了吗"=工作失误。memory中存有各项目关键信息,每次涉及时先读取。
## 核心要求(Maggie 2026-06-17 定义)
按**六个维度**逐段审核,发现问题**全部提示**,并用**修订模式**修改:
1. **内容疏漏** — 该有的没有:漏字、漏法条、漏要件、请求事项不完整、法律依据悬空(讲了主张却没锚定法条)、论证缺环
2. **逻辑错误** — 主体写反/混淆(申请人↔被申请人、原告↔被告)、前后矛盾、论证跳步、因果不成立、举证责任错配
3. **表达不准确** — 法言法语用词不当、口语化、指代不明、一词多义、与法条原文表述不符
4. **错别字** — 含形近字、同音字、标点错误
5. **格式** — 标题层级、编号连续性、字号/加粗一致性、对齐、缩进、书名号/顿号用法
6. **段落** — 多余空段、段落割裂或杂糅、应分未分/应合未合
## 工作流程
### 第0步:定位文件,逐段读透
#### 0a. 动手改之前,先扫一遍\"文件里有没有别人的在先修订\"——硬性闸门,不可跳(2026-06-24 平和外教补贴通知实测,差点污染他人修订)
**任何 tracked 编辑前的第一个动作 = 扫 w:ins/w:del 看作者集合。** 不是\"读完正文顺手看一眼\",是改之前必须先回答\"这份稿子是干净原稿,还是已经有人改过一轮?\"——答错就会在别人的修订上叠加冗余/冲突内容,违反\"他人修订不动\"铁律。
⚠️ **python-docx 的 `paragraph.text` 会骗你**:它返回的是**接受所有修订后**的文本,把已有的 w:ins/w:del 痕迹**完全隐藏**。用 `.text` 逐段读出来是干净通顺的散文,看不出文件其实已含他人一轮修订。2026-06-24 教训:我用 python-docx `.text` 读《外教补贴通知》,看着是干净原稿就直接 tracked_block_replace 加了一条税务赔偿条款;save 后 dump XML 才发现文件早有 `bittersweet`**9 INS + 2 DEL**,且 bittersweet 已经把我想补的那个税务穿透责任点处理得更细(按故意/重大过失分梯度),我的修改既冗余又与之冲突。立即删档止损(原文件未污染),改为先向用户报告\"文件已有 X 的在先修订\"再问要做什么。
**正确的开场探针(zipfile+lxml,不靠 python-docx):**
```python
import zipfile
from lxml import etree
W='{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'
with zipfile.ZipFile(SRC) as z:
dx=etree.fromstring(z.read('word/document.xml'))
ins=dx.findall('.//'+W+'ins'); dele=dx.findall('.//'+W+'del')
authors=set(e.get(W+'author') for e in ins+dele)
print(f"已有修订: INS={len(ins)} DEL={len(dele)} 作者={authors}")
# 非空 → 文件已被改过一轮,逐条 dump INS/DEL 看清别人改了什么,再决定动作
```
- **作者集合为空** → 干净原稿,正常走六维度审核 + 自己的 tracked 修订。
- **作者集合非空** → 文件已含他人在先修订(可能是客户方先改、或团队另一人改过)。**停下来,先做两件事**:① 逐条 dump 每个 INS/DEL 的作者和内容,看清别人改了哪些点、接受态是什么样;② 向用户报告\"这份文件已有 <作者> 的一轮修订(N处),改了 XXX\",并问清\"那位是谁、与本次任务什么关系、要我在其基础上叠加修订还是只评审不动\"。**在用户回话前不要叠加自己的 tracked 改动**——否则容易做出与他人修订重叠/冲突/责任标准不一致的冗余修改。
- 这条与下文\"已有他人修订痕迹的,保持原样不动\"是同一铁律的**前置探测版**:那条讲\"不动\",这条讲\"动手前必须先知道有没有、是谁、改了啥\"。
- 文件通常在 `~/.hermes/cache/documents/`(企微/邮件收到)或 Nextcloud 对应人目录
- 用 zipfile+lxml 提取 document.xml,**逐段**打印,同时标注:是否加粗(b)、对齐(jc)、样式(pStyle)、编号(numPr)、缩进(ind)、以及已有的修订痕迹(ins/del)
- **【动手前强制:先盘清文件里已有谁的修订,再决定改哪里——2026-06-24 平和外教住房补贴实证,栽过】** 读完文件、做任何 tracked 编辑**之前**,必须先用 zipfile+lxml 把全文 `w:ins`/`w:del``author` 分组列一遍:谁改了、改了哪几段、改了什么。**没盘清就动手 = 高概率撞车。** 本会话没注意文件已有"学校法务(bittersweet)"一整轮修订,直接加了自己的税务责任条款,结果与他已写内容主题重叠、责任标准还不一致,只能撤回重来。盘清后:① 他人修订段**保持原样不动**(铁律,只做自己的审查);② 自己的新增**只落在无他人修订的段落**,或与他人修订**不重叠、不冲突**的点;③ 想改的点若他人已处理,先评估他的版本够不够、要不要在其"之外"补,而非覆盖;④ 注意他人 ins 句常与原文用逗号"咬合"(如 bittersweet 新增句以逗号结尾紧接原文收尾句)——删原文那半句会切断他的句子,遇此先问用户。盘清命令:遍历 `document.xml` 的 ins/del,打印 `e.get(qn('author'))` + 文本。;**改之前先跑 0a 的探针确认作者集合**
### 第1步:六维度过一遍,分级输出
把发现的问题分三级,**先报告再动手**:
- **■ 必改(硬伤)**:漏字、主体写反、法条引用错误、错别字——直接改
- **■ 建议改(补强)**:法律依据悬空、论证不完整——改,但说明理由
- **■ 提示项(请用户定夺)**:尊称用法(贵院vs受诉法院)、书名号顿号、落款日期、风格偏好——**不擅改**,列出请用户拍板
报告格式:每条写清【第几段】+【问题】+【性质/依据】+【改法】。
### 第2步:用修订模式修改(绝不裸写XML)
```python
import sys; sys.path.insert(0,'/home/maggie/contract-work')
from contract_docx_lib import ContractEditor
ed = ContractEditor(SRC)
ed._author = '苌莎莎' # 署名规则见下
edits = [(old, new), ...]
for o,n in edits:
ed.tracked_replace(o, n)
ed.save(OUT)
```
- 署名规则:在**莎莎**的文书上修订署"苌莎莎";Doro的合同审查历史上用"WB"。按文书归属人的署名习惯,不确定就问。
- tracked_replace 用字符级diff,纯补字=只产生ins,删改=ins+del
- **markup 清洁度铁律(2026-06-23 邹家监督申请书实测)**:tracked_replace 的字符级 diff 只适合**最小改动**(单字错别字、补一个字、删一个字)。**整词/整句改写**,尤其新旧文本共享字符(如称谓 `法庭``莲都法院` 共享"法"字)会把修订态咬成 `莲都法~~庭~~院``未经~~及~~法庭审理` 之类半字脏标记——**接受所有修订后文本是对的**,但 Doro/莎莎用 OnlyOffice 看的是**修订态**且有格式洁癖,脏 markup = 交付缺陷。规则:整词/整句/大改写一律用**整块删插**(`[del 整段旧][ins 整段新]`,绝不让 difflib 咬共享字);删整段(合并条款删掉一个自动编号列表项)用**段落级标删**让自动编号重排(四→三)。两个补充方法实现(tracked_block_replace / tracked_delete_paragraph)+ 双视图核验 + 全角括号 + validate 误报 见 references/tracked-changes-clean-markup.md
### 第3步:三查后交付(铁律,不可省)
1. `ed.validate()` 返回空列表才算过(查编号连续性、字号一致、加粗规则)
- **误报豁免**:validate 的"不应加粗"规则是按合同正文(不加粗)设计的。诉讼文书的**请求项/标题本就加粗**,ins 继承原段落加粗与原文一致时,这条报警是误报——核对方法:读原始文档同类段落第一个普通run的加粗状态,若原文该体例本就加粗,则放行(2026-06-23 邹家申请书请求一)。
2. 检查所有 w:ins 的 author 正确、字体无缺失(zipfile+lxml读XML逐个查rPr/rFonts)
3. 渲染PDF:`libreoffice --headless --convert-to pdf`,用 pdftotext 提取文字层核对:
- 乱码符号(U+FFFD)数量=0
- "接受所有修订后"的最终文本包含所有预期改动(PDF含删除线文本,连续匹配会失败,必须读docx的w:ins或重建最终文本来验证)
- 未引入不该出现的内容(如管辖异议里别主动提"股权所在地"等自曝点)
4. **双视图核验(Doro/莎莎口径,2026-06-23 起强制)**:交付物给的是**修订态 docx**,但要分别验两个视图——
- **修订态**:用 OnlyOffice 容器内 x2t 渲染(Doro/莎莎实际用 OO 看痕迹,LibreOffice 与 OO 不同源),转 PNG 自查 markup 是否干净(无半字脏标记、无文字重叠)
- **接受态**:脚本剥离 del/unwrap ins/删空列表项后渲染,核对自动编号是否正确重排(删条款后一二三连续无断号)、全角括号生效
- 两套渲染脚本见 references/tracked-changes-clean-markup.md
- **仿宋全角引号**:若用户要求"引号统一为仿宋"——中文弯引号 “ ”(U+201C/U+201D)是中西文模糊字符,所在 run 常 ascii=Times/eastAsia=None,OnlyOffice 按 ascii 渲染成又粗又重的 Times。修法是给含引号 run 显式设 rFonts eastAsia=ascii=仿宋(含数字的 run 要拆,数字保留 Times),改完必须 OO 实渲染确认。完整诊断+脚本见 references/tracked-changes-clean-markup.md
### 第4步:交付 + 说明
- 文件名遵循 file-naming-convention:当事人+文件名称+版本+修改人+日期,如 `…-v4-rev.MJ-20260617.docx`
- MEDIA标签发企微;如要求邮件则发对应人并按规则CC
- 附**审核报告**:改了哪几处(必改/建议分别列)、提示项留给用户定夺的有哪些、以及任何策略性提醒
## 常见硬伤清单(高频复现,重点查)
- **主体写反**:管辖异议/答辩状里"申请人↔被申请人"颠倒——最高频硬伤,必查每一处主谓
- **法条漏字**:引法条要与原文逐字核对。如民诉282条是"更为方便的**外国法院**",漏"外国"是常见疏漏
- **法律依据悬空**:标题/主张讲了某类连接点或要件,正文却没点明法条编号——补锚点
- **称谓不统一**:正文客观陈述用"受诉法院",结尾呼告用"贵院"可并存(提示项,非必改)
- **编号/标题层级**:新增条款标题与内容是一个整体,不拆成两个独立编号(Doro 06-12规则)
- **空段落**:连续两个以上空段往往是多排的行
## 法律内容审核铁律(继承自 legal-research-and-advisory)
- 涉及法条的,必须核实原文有效版本,不凭记忆
- 严格区分"法律依据"与"策略判断/行业惯例",不把后者包装成法律结论
- 法律法规必须是引用时有效的;事实陈述必须有来源;案例引用要案号+法院+日期
- 法律文书总结/归纳必须用法言法语,不口语化改写
## 文风随落款主体定:律师代书 vs 当事人自署(Doro 2026-06-24 徐函纠正,铁律)
**审稿/优化前先看落款主体,再定文风标准——用错标准会被直接退回。**
- **律所/律师署名的文书**(代理词、法律意见、律师函以律所名义发)→ 客观克制,禁情绪化/辩论腔(适用 legal-research-and-advisory 的"律师客观陈述"三段式规则)。
- **当事人/公司自己署名的函**("严正回应""问责函""情况说明",落款是公司+法定代表人签字)→ **保留当事人的情绪与严正语气**,这是客户在为自己发声,理应有立场、有分量。Doro 原话:"保持情绪,因为这是客户发函。"
- 我曾对一封公司署名的《严正回应》主动提"通篇降温去情绪化",被 Doro 纠正——客户函不套律师客观陈述标准。
- **保留**:严正、质问、合理的不满("非同寻常""厚此薄彼""有求必应""公然违背""断难认可"这类有立场的措辞)。
- **仍须守的底线**(即便保留情绪也不能破):① 事实必须准确有据;② 法条引用精准(条款号、原文);③ 不做无证据的人身攻击或诽谤性断言("关系非同寻常"这类影射要么用客观事实坐实、要么收稳,避免将来被对方反诉名誉侵权);④ 把最有力的弹药(如违反保密义务的实锤)排到重心,情绪服务于说理而非取代说理。
- 优化客户函的正确动作 = **保情绪 + 补法律依据 + 弹药排序 + 洗格式**,不是"降温改写"。
## 扫描件 PDF 法条提取(web 源只有图片版时,2026-06-24 广东利益冲突规则实战)
地方律协规则、老版行业规范常只有**扫描版 PDF**(无文本层),`web_extract`/`pdftotext` 提不出字。判别:`pdffonts X.pdf` 无字体行 + `pdftotext` 输出空/全 `\f`。提取办法:
```bash
pdftoppm -png -r 200 scan.pdf img # 转图,200dpi 足够 OCR
# 先用关键词定位目标条在哪几页(避免逐页全 OCR)
for f in img-*.png; do
tesseract "$f" - -l chi_sim 2>/dev/null | tr -d ' \n' \
| grep -q "目标关键词" && echo "$f 命中"
done
tesseract img-04.png - -l chi_sim # 对命中页做完整 OCR
```
- `tesseract` + `chi_sim` 语言包对印刷体法条 OCR 质量足够逐字核(条号、款、关键术语都清晰)。
- OCR 出的文本仍要按"法条款项核查铁律"对待:交叉验证、确认版本施行日期。
- 一个 PDF 常含多个规则合订——先 OCR 找标题页定位目标规则范围,再 OCR 目标条款页。
## 法条核查方法论铁律(Doro 2026-06-23,第五十一条款项事件,两次纠正)
**触发:审核稿引用了"第X条第Y款",或某主张锚定了某法条。** 核"款项准确"与"法条是否真支撑该主张"是审核硬指标,错了就是硬伤。
1. **铁证 = 完整法条原文,不是别人的引用。** 律所文章、专业解读、法律问答、教材转述——全都是"别人的引用",**不能当铁证**。哪怕中伦/最高法知产法庭的解读白纸黑字写"第二款",也只是旁证;必须找到**法条本身的完整原文**逐字逐款确认。我曾拿律所解读当铁证下判断,被 Doro 当场点"铁证只能是完整的法律规定"。
2. **搜索摘要/web_extract 常省略法条开头的款——禁止据摘要判断"第几款"。** 多个权威网页(最高法公报、sipf、知产法庭)的摘要都把第五十一条**第一款"举证期限可以由当事人协商"省略了**,直接从第二款"人民法院指定举证期限的…"显示。我据此误判"十五日"在第一款,把 Doro 写对的"第二款"改成了错的"第一款"。**摘要省略 ≠ 原文**。
3. **必须抓全条原文(含被省略的款)逐款数。** 方法:`curl` 拿原始 HTML,正则切 `第X条(.*?)第X+1条`,看原文换行/全角缩进(`  `另起一款)数款。**两个独立一手源交叉验证**,款数与字句都一致才算定。脚本见 references/statute-citation-verification.md
4. **版本核对:极易误抓旧版。** 同一部规定有多版(如证据规定 2001版 vs 2019修正版,民诉法 2017/2021/2023修正)。抓到后先核施行日期/修正时间——我曾误抓 2001 旧版证据规定(第51条是"质证顺序")来核现行第51条(举证期限),完全张冠李戴。
5. **引用法规年份必须用施行日期,不用公布日期。** 行政法规的"公布日期"和"施行日期"常不同年(如国务院令第584号2010年11月公布、2011年3月施行)。对外引用时以施行日期为准,说"2011年施行的《XX条例》",不说"2010年的条例"——用公布日期会被客户/律师质疑"没有这个版本"。同理,修订版以修订施行日期标注。
6. **法条错配也是硬伤:引的条文必须真能支撑该主张。** 不只查"款项对不对",还要查"这条说的是不是这个事"。Doro 用民诉法第137条("公开审理原则")去支撑"开庭→举证→质证的程序顺序"——137条讲的是公开审理,跟程序顺序无关,是错配。审核时对每个法条锚点都要回原文确认"条文内容 = 主张所需依据",不符就是"法律依据错配",列必改。
## 关联skill
- contract-editor / contract-reviewer:合同专项审查(reviewer+editor分角色)
- litigation-document-preparation:文书制作(非审核)
- legal-research-and-advisory:法律问题咨询(非文书审核)
- file-naming-convention:交付命名规则
## references/
- `references/tracked-changes-clean-markup.md` — 修订态 markup 清洁度、双视图核验脚本、仿宋全角引号修法、**全局字体规范化(中文仿宋/英数 Times,含 OnlyOffice 容器无真仿宋→验属性不验字形的坑)**、validate 加粗误报豁免
- `references/statute-citation-verification.md` — 法条引用一手原文逐款核查 recipe(curl 绕摘要)、已核样本库(民诉法/证据规定/宪法/监督规则现行条文)、检察监督概率评估口径
- `references/legal-opinion-review-checklist.md` — 法律意见书专项审查要点:定性力度与法律后果匹配("不建议"vs"不得")、前后逻辑自洽、法条引用闭环(定义→禁止→后果)、主体信息准确性、实操建议可行性核查
## 结构性改动技巧(段落重排,2026-06-23 邹家 违法点重排)
用户要求调整章节/条款顺序(如"把违法点C挪到压轴")时:
- 段落重排用**接受态物理移动**(lxml 在 body 里 remove + insert 整组段落,含标题+正文段),**不要**用 tracked-move——OOXML 的移动修订在 OnlyOffice 里渲染成大段删除+大段插入,比脏 markup 更难看。
- 自动编号(numPr/numId)的列表项移动后**自动重排**,无需手动改编号;移完渲染接受态核对 (一)(二)(三)… 连续无断号。
- 移动与文字层 tracked 改动可叠加:先做文字 tracked_replace/block_replace(留痕给用户看),再做段落物理移动(结构调整),交付时**明确告诉用户哪些是修订痕迹、哪些是结构重排**(重排不在 markup 里显示)。
- 定位段落用接受态文本前缀匹配(`acc(p).startswith(...)`),避免误匹配。
@@ -0,0 +1,48 @@
# 法律意见书审查要点(Legal Opinion Review Checklist)
审查法律意见书(区别于诉讼文书审核)时,除六维度通用检查外,重点关注以下逻辑和专业性问题:
## 1. 定性力度与法律后果匹配
| 情形 | 正确表述 | 错误表述 |
|------|----------|----------|
| 法律明文禁止 | "不得""法律禁止""违反…的规定" | "不建议""存在风险" |
| 风险提示(无明确禁止规范) | "建议审慎评估""合规风险较高" | "不得""法律禁止" |
| 操作建议 | "建议…""如…则应…" | 混用禁止性语言 |
**2026-07-11实证**:苏州新东方学校(非营利性民办非企业单位)从事广告发布,《暂行条例》第25条明确规定处罚后果(警告→撤销登记+没收+1-3倍罚款),属于"法定禁止"而非"风险提示"。意见书原稿用"不建议"被纠正为"不得"。
**规则**:引用了处罚条款的,定性语言必须匹配处罚力度。有明确法律后果的违法行为,不用"建议"语气。
## 2. 前后逻辑自洽
常见矛盾模式:
- **先宽后严**:开头说"合作范围可以更宽泛",后文却逐项收窄到几乎不能做。如果结论是从严,开头不要先给宽松预期。
- **并列理由实质重复**:第1点和第3点说的是同一件事的不同法条表述(如"非营利性不得经营"和"办学结余全部用于办学"),应合并为一个论点+补强法条,不分列。
- **结论与理由脱节**:给了"可行"的结论,但理由中列举的限制条件实际上使该合作不具可操作性。
**检查方法**:读完全文后,把每个平台/主体的"整体评价"单独提出来,核对与下文具体分析是否一致。
## 3. 法条引用完整性
法律意见书中引法条的标准:
- 不止引"定义条款"(如第2条),还要引"法律后果条款"(如第25条处罚规定)
- 引用链:性质认定(第X条)→ 禁止性规定(第Y条)→ 违反后果(第Z条),三者形成闭环
- 涉及非营利性组织的,《民促法》和《暂行条例》要交叉引用(前者是教育法体系专门规范,后者是民非单位通用规范)
## 4. 主体信息准确
- 统一社会信用代码必须正确(首位5=民政登记社会组织、9=工商登记企业)
- 经营范围/业务范围引用须与公示信息逐字一致
- 主体性质定性(有限公司/民办非企业单位/个体工商户)影响适用法律,必须准确
## 5. 格式/编号统一
- 建议编号:同一层级用相同编号体系(1)2)3)或1. 2. 3.,不混用)
- 错别字高危区:"个人信息"不写"信人信息"、"广告发布"不写"广告发不"
## 6. 实操建议可行性
- 给出的合规路径必须在法律上可行(如建议"由A公司签约承担B学校的广告发布者责任"——需核查广告发布者是事实认定还是合同约定,穿透风险)
- 民办非企业单位变更业务范围须经业务主管单位+登记管理机关双重审批,不同于企业法人的工商变更
- 标明审批难度和不确定性,给客户完整预期
@@ -0,0 +1,101 @@
# 法条引用核查 — 一手原文逐款验证(recipe + 已核样本)
来源事件:邹家民事诉讼监督申请书(2026-06-23)。Doro 两次纠正:先"你再认真核对第五十一条是第几款",再"铁证只能是完整的法律规定,而不能是别人的引用"。我犯过的错:(a) 据搜索摘要误判款项,把对的改成错的;(b) 拿律所解读当铁证;(c) 误抓 2001 旧版核现行版。
## 为什么摘要不可信
多个权威站点(gongbao.court.gov.cn 最高法公报、sipf、ipc.court.gov.cn 知产法庭)在 web_search/web_extract 返回里,会把**法条开头的款省略**,直接从中间某款显示。第五十一条第一款"举证期限可以由当事人协商,并经人民法院准许"在所有摘要里都不见了,导致"指定举证期限…十五日"看起来像第一款,实为第二款。
## 核查 recipe(curl 抓原始 HTML,绕过摘要层)
```bash
# 1. 抓原始页面(不经 web_extract 的摘要)
curl -s --max-time 25 "<官方/权威全文URL>" -A "Mozilla/5.0" | iconv -f utf-8 -t utf-8 -c > /tmp/law.html
# 2. 正则切目标条,看原文换行/缩进数款
python3 -c "
import re
html=open('/tmp/law.html',encoding='utf-8',errors='ignore').read()
txt=re.sub(r'<[^>]+>','',html); txt=re.sub(r'&[a-z#0-9]+;','',txt)
m=re.search(r'第五十一条(.*?)第五十二条', txt, re.S) # 改成目标条号
seg=m.group(1)
# 不要先把空白全删——款与款之间的换行/全角空格(  )就是分款标志
print(repr(seg[:800])) # 看 \n 和 \u3000 位置判断分款
"
```
- 关键:**不要 `re.sub(r'\s+','')` 把换行抹掉再读**,款的边界就藏在换行里。知产法庭 HTML 里每款以 `\n\n  ` 另起,最清楚。
- **两个独立一手源交叉验证**,款数与字句都一致才采信。
- 抓到后**先核版本**:看页面的施行日期/"根据XXXX年…修正"字样,确认是现行有效版而非旧版。
## 已核样本(现行有效,本案用到,可直接复用)
### 最高法《关于民事诉讼证据的若干规定》(2019修正,2020-5-1施行)第五十一条 — 三款
- **第一款**:举证期限可以由当事人协商,并经人民法院准许。
- **第二款**:人民法院指定举证期限的,适用第一审普通程序审理的案件不得少于十五日,当事人提供新的证据的第二审案件不得少于十日。适用简易程序审理的案件不得超过十五日,小额诉讼案件的举证期限一般不得超过七日。
- **第三款**:举证期限届满后,当事人提供反驳证据或者对已经提供的证据的来源、形式等方面的瑕疵进行补正的,人民法院可以酌情再次确定举证期限,该期限不受前款规定的期间限制。
- → "不得少于十五日"在**第二款**。注意:2001 旧版第五十一条是"质证顺序"(原告出示→被告质证…),完全不同,别抓错。
### 民事诉讼法(2023修正,现行)常用条
- **第十四条**:人民检察院有权对民事诉讼实行法律监督。
- **第六十七条**:当事人对自己提出的主张,有责任提供证据(谁主张谁举证)。
- **第七十一条**:证据应当在法庭上出示,并由当事人互相质证。对涉及国家秘密、商业秘密和个人隐私的证据应当保密,需要在法庭出示的,不得在公开开庭时出示。(质证以庭审出示为前提的真正依据)
- **第一百二十九条**:人民法院对决定受理的案件,应当在受理案件通知书和应诉通知书中向当事人告知有关的诉讼权利义务,或者口头告知。
- **第一百三十七条**:人民法院审理民事案件,除涉及国家秘密、个人隐私或者法律另有规定的以外,应当公开进行。离婚案件,涉及商业秘密的案件,当事人申请不公开审理的,可以不公开审理。→ **这是"公开审理原则",不能用来支撑"开庭→举证→质证的程序顺序"(错配)**
### 宪法(2018修正)
- **第五条**:实行依法治国,建设社会主义法治国家;一切国家机关都必须遵守宪法和法律,任何组织或者个人都不得有超越宪法和法律的特权。("职权法定"最直接的锚)
- **第一百二十八条**:中华人民共和国人民法院是国家的审判机关。
### 最高检《人民检察院民事诉讼监督规则》(2021-8-1施行)
- **第二十八条第二款**:当事人对审判、执行人员违法行为申请监督的,不受前款(先行提异议/复议/起诉)限制。
- **第三十条第一款**:当事人认为民事审判程序中审判人员存在违法行为…向人民检察院申请监督的,由审理案件的人民法院所在地同级人民检察院负责控告申诉检察的部门受理。
- **第一百条**:检察院发现同级法院民事审判程序中有下列情形之一的,应当提出**检察建议**(第四项"审理案件适用审判程序错误")。→ 对审判程序违法的监督方式是**柔性检察建议**,非抗诉。
- **第一百零三条**:认为审判人员违法行为认定依据不足的,作"不支持监督申请决定"。
## 律师执业 / 利益冲突 / 保密义务(2026-06-24 徐函事件,已核现行原文)
代表客户向律所/律师问责或审查顾问合同时用。地方律协规则常只有扫描版 PDF(见 SKILL.md「扫描件 PDF 法条提取」用 tesseract OCR)。
### 中华人民共和国律师法(2017修正,现行)
- **第三十八条**:律师应当保守在执业活动中知悉的国家秘密、商业秘密,不得泄露当事人的隐私。律师对在执业活动中知悉的委托人和其他人不愿泄露的有关情况和信息,应当予以保密。但是,委托人或者其他人准备或者正在实施危害国家安全、公共安全以及严重危害他人人身安全的犯罪事实和信息除外。(律师保密义务的法律层级依据——律所擅自把客户盖章文件发给无关第三方=违反此条)
- **第三十九条**:律师不得在同一案件中为双方当事人担任代理人,不得代理与本人或者其近亲属有利益冲突的法律事务。
### 司法部《律师执业管理办法》(司法部令第134号)
- **第二十八条**:律师不得在同一案件中为双方当事人担任代理人,或者代理与本人及其近亲属有利益冲突的法律事务。
### 《广东省律师防止利益冲突规则》(2018版与2025修订版,第八条条号内容一致)
2018版(合同2025-8签订时适用,OCR 自广东律协官网 gdlawyers.net 原始扫描 PDF);2025修订版(粤律协〔2025〕115号,2025-11-1施行,现行,文本源 szrlaw.net)。两版核心一致:
- **第八条【直接利益冲突】**:在担任法律顾问期间,律师或者同一律师事务所的其他律师又在诉讼、仲裁或者其他非诉讼业务中接受该法律顾问单位或者个人的对方当事人或者有利益冲突的当事人委托的,属于直接利益冲突。
- **第十四条**(2025版):直接利益冲突应当主动回避,不得接受委托,已经接受委托的,应当予以解除。
- **第十六条**:律师事务所或者律师遇有间接利益冲突情形时,应征得各方委托人的书面同意;不能征得各方当事人书面同意时,应按处理直接利益冲突的规定进行处理。
- **第十七条**:除本规则规定的利益冲突情形外,发现有可能产生利益冲突的,应及时告知委托人,并征得受影响的各方委托人书面同意。
-**要点**:① "法律顾问期间为顾问单位对方当事人服务"是**直接利益冲突**(不是间接),须回避/解除,不能靠合同里一纸概括预先豁免消解;② 即便按间接冲突,也须就**具体情形个案知情地征得书面同意**,合同"一揽子预先豁免、不再另行出具豁免函"的格式条款站不住,且对客户(甲方)极不利——预先放弃了利益冲突异议权。
### 司法部《律师和律师事务所违法行为处罚办法》
- **第七条第三项**:担任法律顾问期间,为与顾问单位有利益冲突的当事人提供法律服务 = 应处罚的利益冲突违法行为。
## 外籍个人住房补贴免税 + 扣缴义务人责任(2026-06-24 平和外教住房补贴通知,已核一手原文)
审外企/外籍员工津补贴政策、免税承诺条款、扣缴义务相关文件时用。
### ⚠️ 自己栽过的错:别写"经主管税务机关核准/审批"作为免税前提——该审批 2004 年已取消
我审《外教补贴通知》时,第一版意见建议补"免税须经主管税务机关核准确认"。**这是错的。** 国税发〔1997〕54 号原文确有"由主管税务机关核准确认免税",但**国税发〔2004〕80 号自 2004-7-1 起取消了该审批**(国家税务总局政策法规库原文:"取消外籍个人住房、伙食等补贴免征个人所得税审批的后续管理")。免税现在**无前置审批**——只需满足实质要件 + 留存凭证备查。幸亏 Doro 要求"涉及法律法规再核实一次",核一手原文时才发现。**教训:旧规范性文件的程序性条款(审批/备案/核准)极易被后续文件废止,引用前必须查"是否已取消/下放",不能照抄旧文。**
### 免税实质要件(财税字〔1994〕20号 + 国税发〔1997〕54号,现行有效)
- 外籍个人以**非现金形式或实报实销形式**取得的**合理的**住房补贴、伙食补贴、洗衣费,**免征个税**。
- 要件三件套:① 非现金/实报实销(凭票);② 金额合理;③ 留存**有效凭证**备查。**无审批环节**(2004 取消)。
- 写进文件的合规措辞(已用、经核):"在符合税务法规规定的前提下,可享受免税福利"或展开为"在符合实报实销、凭合规有效凭证、金额合理等免税条件的前提下…;不符合免税条件的部分,依法计入工资薪金所得缴纳个人所得税"。**不要**写绝对化承诺"可享受免税福利"(学校为免税结果背书=风险)。
### 政策时效:免税延续至 2027-12-31(财政部 税务总局公告〔2023〕29号)
- 公告第二条原文:"**本公告执行至2027年12月31日**"(一手源:HR政策库 zc.51shebao.com 等多站一致,全文有效,2023-8-18 发布)。
- 居民外籍个人**二选一**:专项附加扣除 OR 八项津补贴免税,不得同时享受,一经选择当年不得变更。
- 给文件加"如国家税收政策调整本通知相应调整"弹性条款是合理建议(政策有到期日),但属可选,问用户。
### 扣缴义务人责任(税收征管法 2015修正,现行)— 用人单位代扣个税
- **第三十条**:扣缴义务人依法律/行政法规履行代扣代收义务;纳税人拒绝的,扣缴义务人应及时报告税务机关。
- **个税法第九条**:以**支付所得的单位或个人**为扣缴义务人(用人单位=外教工资的扣缴义务人,法定,不可由约定免除)。
- **第六十九条**:扣缴义务人应扣未扣、应收不收税款的,由税务机关**向纳税人追缴税款**,对扣缴义务人处应扣未扣税款 50%–3倍罚款。(应扣未扣→税款向纳税人追,扣缴义务人担罚款,一般不加滞纳金——滞纳金只适用"已扣未缴",第三十二条)
- **实务要点(站用人单位/学校立场写条款)**:① 法定扣缴义务不能靠合同免除(约定免除无效,仍可能被罚);② 但可约定"纳税人配合扣缴、对所提供凭证信息真实性负责,因其不配合/提供虚假信息致扣缴义务人受损的,由纳税人担责"——这是站扣缴义务人立场的有效防线(来源:锦天城、大成扣缴义务专文)。虚开发票致学校被稽查处罚的穿透责任,按"故意/重大过失 vs 第三方提供"分梯度处理更稳健(学校法务 bittersweet 的写法)。
## 检察监督概率评估口径(审判程序违法类,非生效裁判再审)
当用户要"客观分析检察院监督概率"时,分两层、别混:
- **受理/立案审查概率**:定性准+管辖对+不受前置限制+证据齐 → 较高。
- **实际发检察建议且法院纠正概率**:审慎偏中/低。减损因素:①监督方式只能是柔性检察建议(规则第100条),可不采纳;②未生效、程序进行中是检察监督冷区,倾向"法院后续可自我纠正"而消极处理(规则第103条不支持决定);③法院有"可补正"回旋空间;④"15日恰为举证下限"是有力旁证但非铁证,可被"巧合/这就是质证准备期"化解;⑤事实主张(如未送达)押在调卷核实上。给区间、点明天花板,别给"很可能成功"的乐观结论。
@@ -0,0 +1,269 @@
# 修订态 markup 清洁度 + 双视图核验
来源:2026-06-23 邹家民事诉讼监督申请书审核(Doro 给 7 点修改指示)。教训:第一遍用 `tracked_replace`(字符级 diff)做整句改写和称谓替换,接受态文本正确,但**修订态被 difflib 咬成半字脏标记**(`莲都法~~庭~~院``未经~~及~~法庭审理``一百二十八条~~切~~国家机关`)。Doro 用 OnlyOffice 看的是修订态且有格式洁癖 → 必须重做。
## 核心规则
| 改动类型 | 用什么 | 为什么 |
|---|---|---|
| 单字错别字、补一个字、删一个字 | `tracked_replace`(字符级,库自带) | 改动点孤立,diff 干净 |
| 整词替换(尤其新旧共享字,如 法**庭**→莲都法**院**) | `tracked_block_replace`(整块 del+ins) | 阻止 difflib 咬共享字产生半字 |
| 整句/整段改写 | `tracked_block_replace` | 同上,markup 是清爽的[删旧句][插新句] |
| 删整段(合并条款、删一个自动编号列表项) | `tracked_delete_paragraph`(段落级标删) | 让自动编号重排(删请求三→请求四自动续成三) |
判据:**只要新旧文本有共享字符且改动跨多字,就别用 tracked_replace,改用 block。**
## 两个补充方法(库 contract_docx_lib.py 没有,用 types.MethodType 挂到实例上)
```python
import sys, copy, types
sys.path.insert(0,'/home/maggie/contract-work')
from contract_docx_lib import ContractEditor, qn, XML_SPACE
from lxml import etree
ed = ContractEditor(SRC); ed._author='小Maggie' # 署文书归属人
# ---- 整块替换:[del 整段旧][ins 整段新],markup 干净 ----
def tracked_block_replace(self, old_text, new_text):
for p in self.body.findall(qn('p')):
runs=p.findall(qn('r'))
if not runs: continue
full=''.join(''.join(t.text or '' for t in r.findall(qn('t'))) for r in runs)
if old_text not in full: continue
start=full.index(old_text); end=start+len(old_text)
rpr=None; pos=0
for r in runs:
rt=''.join(t.text or '' for t in r.findall(qn('t')))
if pos+len(rt)>start:
rpr=r.find(qn('rPr'))
if rpr is not None:
rpr=copy.deepcopy(rpr); self._ensure_rfonts_complete(rpr)
if rpr.find(qn('sz')) is None and self._body_rpr is not None:
bsz=self._body_rpr.find(qn('sz'))
if bsz is not None:
etree.SubElement(rpr,qn('sz')).set(qn('val'),bsz.get(qn('val')))
break
pos+=len(rt)
pos=0; first=last=None; prefix=suffix=''
for idx,r in enumerate(runs):
rt=''.join(t.text or '' for t in r.findall(qn('t')))
re_=pos+len(rt)
if re_>start and pos<end:
if first is None: first=idx; prefix=full[pos:start]
last=idx; suffix=full[end:re_] if re_>end else ''
pos=re_
ref=runs[first]; parent=ref.getparent(); ip=list(parent).index(ref)
for idx in range(last,first-1,-1): parent.remove(runs[idx])
i=ip
if prefix: parent.insert(i,self._mk_run(prefix,rpr)); i+=1
parent.insert(i,self._mk_del(old_text,rpr)); i+=1
parent.insert(i,self._mk_ins(new_text,rpr)); i+=1
if suffix: parent.insert(i,self._mk_run(suffix,rpr))
return True
return False
ed.tracked_block_replace=types.MethodType(tracked_block_replace,ed)
# ---- 段落级修订删除:整段(含段落标记)标删,自动编号重排 ----
def tracked_delete_paragraph(self, search_text):
p=self.find_para(search_text)
if p is None: return False
for r in list(p.findall(qn('r'))):
rpr=r.find(qn('rPr')); texts=r.findall(qn('t'))
d=etree.Element(qn('del')); d.set(qn('id'),self._next_id())
d.set(qn('author'),self._author); d.set(qn('date'),self._revision_date)
nr=etree.SubElement(d,qn('r')); nr.set(qn('rsidDel'),self._rsid)
if rpr is not None: nr.append(copy.deepcopy(rpr))
for t in texts:
dt=etree.SubElement(nr,qn('delText')); dt.set(XML_SPACE,'preserve'); dt.text=t.text
idx=list(p).index(r); p.remove(r); p.insert(idx,d)
ppr=p.find(qn('pPr'))
if ppr is None: ppr=etree.Element(qn('pPr')); p.insert(0,ppr)
rpr=ppr.find(qn('rPr'))
if rpr is None: rpr=etree.SubElement(ppr,qn('rPr'))
dem=etree.Element(qn('del')); dem.set(qn('id'),self._next_id())
dem.set(qn('author'),self._author); dem.set(qn('date'),self._revision_date)
rpr.insert(0,dem) # 段落标记标删 → 接受后整段消失,编号重排
return True
ed.tracked_delete_paragraph=types.MethodType(tracked_delete_paragraph,ed)
```
执行顺序:小改动(tracked_replace) → 称谓/整句(block) → 大改写(block) → 删段(delete_paragraph) → save。
## 半角括号 → 全角(自动编号子标题 (一)→(一))
子标题 `(一)(二)` 是自动编号,半角括号根在 numbering.xml 的 lvlText `(%1)`,不在正文。改 numbering.xml 一次性全改最干净(不要去正文里找,找不到):
```python
import zipfile, io
from lxml import etree
W='{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'
with zipfile.ZipFile(SRC) as z:
num=etree.fromstring(z.read('word/numbering.xml'))
for lt in num.iter(W+'lvlText'):
v=lt.get(W+'val')
if v and ('(' in v or ')' in v):
lt.set(W+'val', v.replace('(','').replace(')',''))
new=etree.tostring(num,xml_declaration=True,encoding='UTF-8',standalone=True)
buf=io.BytesIO()
with zipfile.ZipFile(SRC) as zin, zipfile.ZipFile(buf,'w',zipfile.ZIP_DEFLATED) as zout:
for it in zin.infolist():
zout.writestr(it, new if it.filename=='word/numbering.xml' else zin.read(it.filename))
open(OUT,'wb').write(buf.getvalue())
```
注意:`、`(如 一、二、 和 %1、)不受影响,只动含半角圆括号的 lvlText。
## 🔴 插入新编号条款前:先判"中文编号是自动编号 还是 手动文字"——`numId=0` = 无编号(2026-06-24 平和外教通知实测,第一版栽了)
要在文件中**插入一个新的带编号大条款**(如 Doro 要"把追回权抽成单独第五条,囊括所有情形")时,**绝不能假设"四、""五、"这些中文编号是自动编号**。判错会让新条款不显示编号、且原"五、其他说明"不顺延。
**判别(动手前必做)**
```python
# 1. 看标题段的 numPr
ppr=p.find(W+'pPr'); numpr=ppr.find(W+'numPr') if ppr is not None else None
nid=numpr.find(W+'numId').get(W+'val') if numpr is not None else None
# 2. 看 numbering.xml 里这个 numId 到底定义了没
# list 出所有 <w:num w:numId=...> 。若标题段挂的 numId 不在其中 → 不是真自动编号
```
**关键陷阱**`<w:numId w:val="0"/>` 是 OOXML **特殊值=取消编号/无编号**,numbering.xml 里**根本不会有 numId=0 的定义**。本会话"四、违规处理细则""五、其他说明"段都挂 `numId=0`,我误判成"自动编号、插同级会自动续号",构造了 numId=0 的新段落——结果 OO 渲染里新条款**完全不显示编号**、"五、其他说明"也没变"六、"。一查 numbering.xml:只有 numId=1/2/3,**没有 0**。再查标题段 run 文本:直接是 `"四、违规处理细则"``"五、其他说明"`——**"四""五"是手打进正文的文字字符,不是自动编号生成的**。
**正确判据**
- run 文本里**肉眼能看到**"四、""五、"这些字 + 段落 numId=0/无 numPr/numId 不在 numbering.xml → **手动文字编号**
- run 文本里**看不到**编号字(只有"违规处理细则"无"四、")+ 段落挂了真实存在的 numId → **自动编号**(numFmt=chineseCounting,lvlText='%1、')。
**手动文字编号的插入做法**(本会话最终正确版):
1. 新条款文本**自己写上编号字**:"五、无论发生上述何种违规情形,……追回……全部免税住房补贴。"(复制相邻标题段的 pPr+rPr 做格式模板,但不靠 numPr 出号)。
2. 新段落作为整段插入修订:pPr/rPr 里塞 `<w:ins>`(段落标记标插),正文 run 用 `_mk_ins` 包裹,author=自己。
3. **手动把后续编号往后顺延**:原"五、其他说明"用 tracked_block_replace 把"五、其他说明"→"六、其他说明"(手动改字,留痕)。
4. 渲染**接受态**用 vision 核对:"四、…→ 五、(新条款) → 六、其他说明" 连续无重号——本会话改对后 OO 实测通过。
**自动编号的插入做法**(对照,仅当确属自动编号时):插一个挂同 numId 的同级段落,编号会自动续;原后续条款自动顺延,**无需手动改编号字**(见本文件"结构性改动技巧"段的 numPr 自动重排)。
⚠️ 顺带的衔接坑:抽条款时若要删的原文句与他人(bittersweet) ins 用逗号"咬合"("…索赔主张【bittersweet逗号】同时…追回全部【原文】"),**只标删原文那半句、不碰他人 ins 的逗号**(铁律:他人修订不动);接受态以逗号收尾虽不完美,但独立新条款紧随其后能化解观感,宁可这样也不改他人标点。
## 仿宋全角引号修复(OnlyOffice 把弯引号渲染成 Times)
**症状**:正文是仿宋,但中文弯引号 “ ”(U+201C/U+201D)显示成又粗又重的西文 Times New Roman 引号,和仿宋正文不协调。Doro 2026-06-23 要求"引号统一为仿宋的全角"。
**根因**:弯引号是"中西文模糊字符"。这些引号所在 run 的 rFonts 往往 `ascii=Times New Roman, eastAsia=None`(eastAsia 继承样式里的仿宋)。OnlyOffice 对 **eastAsia 未显式设定**的模糊字符按 **ascii 字体**渲染 → 走了 Times。诊断:遍历所有含 U+201C/U+201D 的 run,打印 `rFonts/@ascii``@eastAsia`,会看到 ascii=Times、eastAsia=None。
**修法**:给所有含引号的 run 显式设 rFonts。
- **纯引号 / 引号+中文的 run**:`ascii=eastAsia=hAnsi=cs=仿宋, hint=eastAsia`(ascii 也设仿宋,彻底消除模糊字符歧义——只设 eastAsia 在某些 OO 版本仍可能走 ascii)。
- **引号+拉丁数字混排的 run**(如 `“2026浙1102…`):**拆 run**——引号片段走仿宋,数字片段保留 `ascii=Times New Roman`。否则给整 run 设仿宋会把"2026"也变仿宋。拆法:按字符是否∈`{U+201C,U+201D}`分组,逐组生成新 run(引号组设仿宋、非引号组设 Times),原 run 删除、按序 insert 回去。
```python
W='{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'
def qn(t): return W+t
FANG='仿宋'
def has_latin(s): return any(c.isascii() and c.isalnum() for c in s)
for p in list(root.iter(qn('p'))):
for r in list(p.findall(qn('r'))):
txt=''.join(t.text or '' for t in r.findall(qn('t')))
if '\u201c' not in txt and '\u201d' not in txt: continue
rpr=r.find(qn('rPr')); rf=rpr.find(qn('rFonts')) if rpr is not None else None
if not has_latin(txt): # 纯引号/中文:整 run 设仿宋
if rf is not None:
for a in ('ascii','eastAsia','hAnsi','cs'): rf.set(qn(a),FANG)
rf.set(qn('hint'),'eastAsia')
else: # 含数字:按引号/非引号拆 run
import copy
segs=[]; cur=''; cur_q=None
for c in txt:
isq=c in '\u201c\u201d'
if cur_q is None: cur_q=isq; cur=c
elif isq==cur_q: cur+=c
else: segs.append((cur,cur_q)); cur=c; cur_q=isq
if cur: segs.append((cur,cur_q))
parent=r.getparent(); idx=list(parent).index(r); parent.remove(r)
for seg,isq in segs:
nr=etree.Element(qn('r'))
if rpr is not None:
nrpr=copy.deepcopy(rpr); nr.append(nrpr)
nrf=nrpr.find(qn('rFonts'))
if nrf is None: nrf=etree.SubElement(nrpr,qn('rFonts')); nrpr.insert(0,nrf)
if isq:
for a in ('ascii','eastAsia','hAnsi','cs'): nrf.set(qn(a),FANG)
nrf.set(qn('hint'),'eastAsia')
else:
nrf.set(qn('ascii'),'Times New Roman'); nrf.set(qn('hAnsi'),'Times New Roman')
nt=etree.SubElement(nr,qn('t')); nt.set('{http://www.w3.org/XML/1998/namespace}space','preserve'); nt.text=seg
parent.insert(idx,nr); idx+=1
```
**验证**:遍历所有含引号字符的 run,断言 `rFonts/@eastAsia=='仿宋'`,计数应等于全文引号字符数。**OO 渲染确认**:x2t 转 PDF 裁剪含引号区域,目视引号是否纤细、与仿宋协调(不再是重弯钩 Times)——`hint=eastAsia` 不一定够,必须 OO 实渲染验。
**字体诊断通法**:正文中文是不是仿宋?查 styles.xml 的正文样式 rFonts(本会话正文 3333 字 eastAsia=None 全继承样式里的"仿宋")。引号异常往往是局部 run 覆盖了样式字体。
## 全局字体规范化(中文仿宋 / 英数 Times New Roman)
来源:2026-06-23 邹家 v8→v9,Doro 要求"引号统一仿宋 + 中文仿宋 + 英文/数字 Times New Roman"。这是 Doro/Maggie 的**通用排版规范**,不止引号——整篇都要中文走仿宋、拉丁字母与阿拉伯数字走 Times。引号修法见上一节,本节是**全篇 run 的一次性归一**(上一节是引号专项,本节覆盖全文)。
**做法**:遍历每个 run,按字符类别分组,混排 run 拆开,逐组设 rFonts。分类口径:
- CJK 汉字 + 中文标点(。,、;:)→ `eastAsia=ascii=hAnsi=cs=仿宋, hint=eastAsia`
- 拉丁字母 + 阿拉伯数字 → `ascii=hAnsi=Times New Roman`(eastAsia 保留仿宋兜底)
- 弯引号/中文全角符号 → 仿宋(同 CJK,见上一节拆法)
混排 run(如 `浙1102民初2078号``HUAXIN XU 徐华鑫`)必须**拆 run**——给整 run 设一种字体会污染另一类字符。拆法同引号节:按字符类别切片,逐片 deepcopy rPr 后改 rFonts,原 run 删除按序 insert 回去。
**验证(Doro 口径,必做)**:改完统计全文 run 字体属性分布,按四类断言计数:
```
最终文件字体属性:
NNNN CJK 仿宋
NNN LATIN Times New Roman
NNN PUNCT 仿宋
NN QUOTE 仿宋
规范达标: ✅ 中文全仿宋 + 英数全 Times
```
读 word/document.xml 所有 run,逐字符按类别归到该 run 的 rFonts 目标字体;发现"中文 run 的 eastAsia≠仿宋"或"纯拉丁 run 的 ascii≠Times"即为漏网,回去补。
### ⚠ OnlyOffice 容器没有真仿宋字体——验字体看属性,不看字形
用 OO 容器 x2t 渲染来**目视**核验时要警惕:**生产 OO 容器通常没装真·仿宋**,会把"仿宋"字体名回退映射到 Noto Serif(字形偏宋体)。所以渲染图里中文看着像宋体 **≠ 文件错了**——文件 rFonts 的字体名属性是"仿宋"才是关键,Doro 本机有真仿宋会正确显示。
- 验"中文是不是仿宋":**查 docx 的 rFonts/@eastAsia 属性值**(程序断言),**不靠 OO 渲染图字形**判断。
- OO 渲染图只用来验**布局**(无缺字方框/无字体回退 tofu/无文字重叠/英数确为 Times 衬线)——vision_analyze 看。
- **别污染生产容器**:若为渲染临时往 OO 容器塞了字体映射,验完必须移除恢复,不留临时字体污染生产环境。
## 双视图核验
### A. 修订态(Doro/莎莎用 OnlyOffice 看痕迹)→ 用 OO 容器 x2t,不用 LibreOffice
LibreOffice 与 OnlyOffice 不同源,必须用 OO 口径验 markup。
```bash
docker cp v_final.docx nextcloud-onlyoffice-1:/tmp/z.docx
docker exec nextcloud-onlyoffice-1 bash -lc '
cat >/tmp/zx.xml <<XML
<?xml version="1.0" encoding="utf-8"?>
<TaskQueueDataConvert xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<m_sFileFrom>/tmp/z.docx</m_sFileFrom><m_sFileTo>/tmp/z.pdf</m_sFileTo>
<m_nFormatTo>513</m_nFormatTo><m_bIsNoBase64>false</m_bIsNoBase64>
</TaskQueueDataConvert>
XML
cd /var/www/onlyoffice/documentserver/server/FileConverter/bin && ./x2t /tmp/zx.xml'
docker cp nextcloud-onlyoffice-1:/tmp/z.pdf /tmp/markup.pdf
pdftoppm -png -r 150 /tmp/markup.pdf /tmp/mk # 转图 vision_analyze 查脏标记
```
查点:每个 del/ins 是整段配对、无半字、无文字重叠。
### B. 接受态(成稿)→ 程序剥离修订后渲染,核对编号/括号
```python
# 接受所有修订:unwrap ins(留子元素)、删 del、删被标删的空列表段
for ins in list(doc.iter(W+'ins')):
par=ins.getparent(); idx=list(par).index(ins)
for ch in list(ins): par.insert(idx,ch); idx+=1
par.remove(ins)
for d in list(doc.iter(W+'del')):
par=d.getparent()
if par is not None: par.remove(d)
for p in list(body.findall(W+'p')): # 删 tracked_delete_paragraph 留下的空列表项
txt=''.join((t.text or '') for t in p.iter(W+'t'))
ppr=p.find(W+'pPr'); has_num=ppr is not None and ppr.find(W+'numPr') is not None
if has_num and txt.strip()=='': body.remove(p)
```
核对:删条款后自动编号一二三连续无断号、全角括号生效、U+FFFD=0。
## 自查清单(交付前)
- [ ] 整词/整句改写用了 block,不是 tracked_replace(修订态无半字)
- [ ] 删段用 delete_paragraph,接受后编号重排无断号
- [ ] 全角括号改在 numbering.xml
- [ ] validate() 过(请求项/标题加粗误报已豁免核对)
- [ ] ins author = 文书归属人、字体无缺失
- [ ] OO 渲染修订态 markup 干净(vision 查)
- [ ] 程序剥离后接受态编号/括号正确
- [ ] 引号统一仿宋全角(含引号 run eastAsia=仿宋,OO 渲染确认不再是 Times;含数字的拆 run)
- [ ] 全局字体规范:全篇中文 run eastAsia=仿宋、拉丁/数字 run ascii=Times(混排已拆 run);用属性断言四类计数核验,**不靠 OO 字形**(容器无真仿宋,会回退宋体;OO 图只验布局)
- [ ] 所有法条核权威原文(宪法 2018 修正、民诉法 2023 修正——条号会变,不凭记忆)。**精确到正确款项**:2026-06-23 Doro 自己把"不得少于十五日"写成证据规定第五十一条**第二款**,实际在**第一款**(第二款是补正不受期间限制)。审核职责含纠正委托人的法条款项笔误,逐条核到款。