# 2026-06-10 · G9d:ruled 表结构重建 —— TEDS 0.129 → 0.419,验收门(≥0.2)通过

## TL;DR

G9d(表格覆盖,G9 最后一个验收门)完成。两条线并进:

1. **评分代理卫生**(对称适用,先拿诚实基线):全空网格过滤 + 行对齐 DP + 取消"空==空"伪匹配 → 原 0.141 修正为 **0.129**(之前的分里有伪匹配成分);
2. **ruled 路径结构重建**(本体工程):留白通道列 + 规则线分带行 + 失败二分重试 → **TEDS 0.419**(3.2× 基线)。

NID 0.781→**0.792**、MHS 0.677→**0.685** 同步新高(假表不再吞文本)。对 Docling:NID 0.822 / TEDS 0.474 / MHS 0.643。三件套零回归,bialetti 双真表完好,100+ 测试绿,clippy 0。

## 起点诊断:丢分在哪

对 2305-pg9 同一张表,ODL 出 6×8、我方出 15×4——**行过分割 + 列欠分割**,这是结构重建问题,不是检测问题。逐文档盘点 ODL 的表后发现分数构成三类:

| 类型 | 例 | 处置 |
|---|---|---|
| ODL 发全空表(图内线框,无字) | 2305 的 12 张里 6 张 filled=0 | 评分对称过滤(度量卫生) |
| 结构不一致 | pg9 15×4 vs 6×8;redp5110 网格行错位 | 本体工程(本次主体) |
| 真实漏检 | normal_4pages 韩文 4×3、2305 p10、redp5110 缺 2 张 | 逐个诊断修复 |

## 评分代理修正(scripts/eval/score.py,全部对称适用)

- `_is_table` 增加**全空网格过滤**:零内容网格是图内线框,内容加权指标无可比对象;我方因填充率否决永不发这种表,被它占分母是在度量"线框检测"。
- `_teds_one` 原来按**绝对行号**比单元格:一侧多一个表头行,后续全部数据行级联错位、内容分全灭。真 TEDS 是树编辑距离,允许行插删。改为**单调行对齐 DP**(行配对最大化逐格匹配,镜像树编辑的行操作);不匹配行仍按 max-行数分母稀释。
- `_row_sim` 不再给"两边都空"的格记分(空==空伪匹配曾让我方稀疏格白拿分——修正后 2305 反而从 0.050 落到 0.032,这是分数变诚实)。

诚实基线:**TEDS 0.129**(原报 0.141)。

## ruled 路径重建(crates/docparse-core/src/table.rs)

原型先在 pg9 真数据上验证(Python):墨迹并集恰好 8 个 span、列间隙均匀 8.4pt(0.94em),基线间隙清晰双峰(行内 5.5–7.4pt vs 行间 13.4–14.4pt)。然后落 Rust:

1. **通道列** `column_spans`:全行 chunk x 区间取并,≥0.5em 的留白即列分隔。词间空隙(~0.25em)被其他行墨迹闭合;居中/右对齐数字列(左缘漂移、旧左缘聚类失效的根因)直接恢复。
2. **双峰逻辑行** `logical_groups`:相邻基线间隙排序后找最大跳变(>1.6×),小间隙绑定为一逻辑行(OTSL/HTML 叠行、表头换行)。均匀间距不合并;最大组 >4 行视为切错、回退单基线行。
3. **规则线分带**:组内内部规则线把基线切成带。**B 先试**(带=逻辑行,适配"每行有线"的栅格表;有内部线背书时放开单元格长度门——韩文政务表单元格本就是段落)→ 不成再 **A**(带内双峰细分,适配 booktabs 中线表)。B 在线疏时因行数不足自然落空,无需显式判别。
4. **失败二分重试** `emit_ruled`:x 容差分组会把"表+下方带线图"链成一个候选区(2305 p10 被 60 条基线、1 个通道的废区埋掉)。整组失败时按最大 y 间隙二分递归重试;长表整组先成功、永不被切。
5. **结构门** `is_tabular`:旧左缘聚类实际兼任检测门,通道列弱得多(代码框/词云也有通道)。补回同强度门:≥3 逻辑行、每列填充 >60%、单元格长度**中位数** ≤25(允许一列长 Description——redp5110 定义表;均值会误杀)。ruled 不设数字证据门(规则线已是强证据,纯文本键值表合法)。

## 中途踩过的门(实现-测量-回退记录)

- 数字证据门(仿 borderless)→ 误杀 redp5110 键值表 → 撤;
- 均值长度门 → 误杀带 Description 列的定义表 → 改中位数;
- A 先 B 后 → A 在密线表上抢先接受更碎网格(redp5110 0.859→0.746)→ 交换为 B 先。

## 记分牌(vs ODL,LTR 12 份)

| 文档 | TEDS 前 | 后 | 备注 |
|---|---|---|---|
| 2305-pg9 | 0.060 | **0.804** | 5×8,数据行与 ODL 逐字一致 |
| redp5110 | 0.496 | **0.859** | 4/4 全检出(二分解锁 2 张) |
| 2206 | 0.157 | **0.421** | 结构修复 |
| normal_4pages | 0.000 | **0.400** | 韩文 4×3(B 模式,段落格) |
| 2305 全文 | 0.032 | **0.264** | p10 "Data set" 解锁 |
| 2203 | 0.161 | 0.184 | 余差=图内嵌表 |
| amt | 0.000 | 0.000 | 参照局限(ODL 把分解图标签当 2×2 表) |
| **汇总** | **0.129** | **0.419** | **G9d 验收门 ≥0.2 通过** |

NID 0.781→0.792、MHS 0.677→0.685(skipped_2pages 假表清除 NID +0.09;2305 MHS +0.09)。对 Docling:0.822 / 0.474 / 0.643(前 0.817/0.154/0.629)。

参照局限记录:skipped_2pages 我方检出韩文 3×10 技术分类网格(真实存在,ODL 无)→ 该文档 TEDS 0 但不进分母;amt 不追(表化图注是错误行为)。

## 经验

- **"结构修复"优先于"检测开门"**:本次 TEDS 翻三倍,检测门一个没放宽(P1c 教训保持),全部来自已检出表的结构质量与评分卫生。
- 行对齐 DP 修复前,结构改进在记分牌上**不可见**(绝对行号级联错位把一切归零)——先修尺子再调参,又一例"分数可疑先怀疑管线"。
- 临时调试(环境变量 eprintln)用完即删;结构性编辑继续用 Edit 工具+grep 验证。
