# Devlog · 记分牌诚实化第二轮:TEDS 配对/过滤 + 页眉检测 bug + NFKC

> 日期:2026-06-10 · 方法:逐指标 diff 找"测量 bug vs 真实差距",同会话已三次发现管线低估 · 承接 [chunk-order-fix](2026-06-10-chunk-order-fix.md)

把 TEDS 与 MHS 也按 NID 那套"逐项 diff、区分管线 bug 与能力差距"过了一遍,找到 1 个真实产品 bug + 3 个测量/归一问题,全部确定性、零回归。

## TEDS(表格)——两个测量纠偏

1. **按索引配对 → 按内容配对**:`teds()` 原来 `pts[i]` vs `gts[i]` 比,但两系统表的发射序、检出子集都不同 → 正确抽出的表被拿去跟无关表比。redp5110:我方抽对了 Special-register/Global-variable 表(per-pair=1.0)却因索引错位拉到 0.184。改贪心最优相似配对,未匹配表计 0(recall 仍诚实)。**redp5110 0.184→0.432**。
2. **只评 2D 表**:ODL 把 1×N/N×1 碎片(2203 的 1×2 页码位、图表坐标轴行,13 张里 5 张)当表,污染分母。对 pred/gt 对称过滤 `≥2 行且 ≥2 列`。边际 +0.005。
- **聚合 TEDS:vs ODL 0.044→0.098、vs Docling 0.110→0.187**(产出未变)。剩余低分主因是真实**检出 recall**(无框学术表),非已检出表的结构错。

## MHS(标题)——一个真 bug + 一个归一

3. **真 bug:跑页眉漏过滤 → 误判为标题**。2305 有 7 个 `"<页码> M. Lysak, et al."` verso 页眉被当成标题。两处根因:
   - `normalize_repeat` 逐字符折数字:`"2 M.Lysak"→"# m..."` 但 `"10 M.Lysak"→"## m..."`,多位/单位页码不匹配 → 跨页计数分散。改为**连续数字折成单个 `#`**。
   - 页边带用行**中心** cy 判定:页眉 cy=696.6 比 12% 边界 697 低 0.4pt → 漏掉。改用行**上沿/下沿**判定(探入即算)。
   - **2305 MHS 0.488→0.647**,7 个假阳性全清;跨页重复阈值仍兜假阳性,零回归。
4. **NFKC 归一**(score.py):连字 `ﬁ→fi` 等——我方正确展开、ODL 保留码点 → 同词被判不同。对称 NFKC。连带**抬 NID**(连字密集的学术文:2305-pg9 0.990→1.000、2305 0.921→0.939、2203 0.936→0.945)。

## 结果(零回归:41 core 单测、clippy 零 warning、三件套不变)

| 同台 | NID | MHS | TEDS |
|---|---|---|---|
| vs ODL（12）| 0.761→**0.764** | 0.614→**0.627** | 0.044→**0.098** |
| vs Docling（10）| 0.832→**0.833** | 0.625→**0.645** | 0.110→**0.187** |

## 教训(再次印证)

本会话**四个记分牌大跳全是管线/测量 bug,非解析能力变化**(列表漏算、chunk 栏序、TEDS 配对、页眉漏滤)。分数可疑时**先怀疑管线**。唯一真实产品 bug(页眉)也靠"逐文档看假阳性集"定位——agreement 指标的 onlyours/onlyodl 差集是最快的 bug 探针。
