# Devlog · N4 无框表格检测（数据驱动，含 Docling 同台量化）

> 日期：2026-06-09 · 里程碑：[plans/n4-borderless-tables.md](../plans/n4-borderless-tables.md) · 状态：✅ 首个增量完成
> 结果：对齐驱动的无框表格检测；与 Docling 表格检出召回 **1/6 → 3/6**；检出真实学术表；零正文回归

---

## 1. 目标与依据

N1 同台数据坐实：含表 born-digital 文档表格检出召回仅 **1/6**、TEDS≈0——学术 PDF 多为**无框**表格，是与 Docling 的最大结构差距。N4 用 `compare_docling.py` 作**反馈回路**，数据驱动地补无框表格。

## 2. 实现

`core::table::detect_borderless_tables(chunks, exclude)`：靠**列对齐**而非 ruling line。
- 行重建（共基线）→ 行内按大间隙（>1.5em）切 cell；
- 区域生长：连续行且 cell 左缘对齐到稳定列（容差内）；
- 成表门控：≥3 行、≥2 列、列填充率 ≥50%。
- interpreter 在**有框检测之后**、对未落入有框表的 chunk 再跑，结果并入 IR。

## 3. 最大坑：双栏版面 ≈ 双栏表格

首版在 1901/2408 上检出 **25/35 张"表"**——**2 栏学术论文的页面版面**本身就是"2 列 × 多行的网格"，被误判。这是无框检测的根本难点。

**修法——内容门控（关键判别）**：表格单元格**短、常含数字**；版面"列"是整行散文。加：
- `平均单元格字符 > 25` → 拒（散文/版面）；
- `列数 < 4 且 数字单元格占比 < 15%` → 拒（窄表需数字证据）。

效果：1901 **25 → 6**、2408 **35 → 3**、lorem 仍 **0**。检查 6 张均为**真实表**：网络结构表（Convolution/MaxPooling/maps:128…）+ 实验结果表（ABBYY et al.[48] 40.5 26.1…）。

## 4. 量化（compare_docling.py 反馈回路）

| 指标 | N4 前 | N4 后 |
|---|---|---|
| 表格检出召回（Docling 有表的 LTR 文档）| **1/6** | **3/6** |
| 含表子集 TEDS | 0.006 | **0.028** |
| born-digital LTR NID | 0.600 | 0.601 |
| 解析 | 13/13 | 13/13，0 panic |

召回翻倍；TEDS 仍低——**检出表 ≠ 结构对齐 Docling**：列/行切分、合并单元格、单元格文本渗漏与 Docling 模型不同，且 TEDS 当前是结构代理。结构精度是后续细化。

## 5. 验证

- **零误判**：lorem 0 表；1901 正文（摘要）仍为散文非表；双栏版面不再误判。
- **零回归**：lorem 387 / bialetti 3831 chunk 不变；1901/2408 仅 +6/+3 表元素；三件套文本不退化。
- **确定性** 20/20；clippy 零 warning；单测 **44**（core 26，+3 无框表）。

## 6. 已知限制（诚实标注）

- **结构精度低**（TEDS 0.028）：列推断/行切分粗、**合并单元格未做**、**单元格文本渗漏**（邻近图注/说明被并入）。
- **过检残留**：数字密集的公式/数组可能被当表；门控偏召回。
- **单元格词粘连**（`maps:128,k3,s1,p1`）：CMR 等字体词距问题（M1 遗留），非 N4。
- 多栏左列重排（M3 遗留）、列表层级、标题分级（MHS 仍 0.257）未在本增量。
- TEDS 仍为结构代理，未换 APTED。

## 7. 下一步

N4 续：列推断（修 M3 多栏左列 + 提 TEDS 结构精度）、合并单元格、标题分级（提 MHS）、单元格文本边界（防渗漏）。或转 N2 服务化 / N5 安全预检。
