Documents that underline many full-width lines (dense CJK business docs,
legal redlines, 10-K section links) produce span-similar rules at 3+
y-levels — exactly what the repeated-ruling filter treats as table
rulings, so every semantic underline on such pages was discarded. Three
changes fix detection without re-marking real tables:
1. Snug-owner rescue: a rule survives the repeated-ruling filter when
the union of touching text runs on its baseline row owns it (rule
contained within the union's span +0.75em, runs cover >=60% of the
rule, no column-sized gaps between runs). Table row separators fail
ownership: they overshoot their cells' text or match gapped items.
Same-row segmented rules (column-header separators) always stay
discarded, and a rule enclosed by a drawn cell-sized box (rect-grid
tables) is never rescued.
2. Vertical window widened 0.35em -> 0.72em below the baseline: CJK
layouts draw underlines under the full em box, measured at ~0.67em.
3. Prose-table guard in the positions-path suppressor: a detected
'table' whose cells hold flowing prose (>=30% of cells over 100
chars) is a detection artifact of boxed callouts + stacked rules,
not a real table — suppressing there erased every underline on the
page.
Also fixes cluster_x_positions fabricating phantom table columns from
style-split continuation runs (touching items, gap <2pt, now feed one
column start) — the fix that keeps rect-grid table shapes stable while
underlined links inside cells are correctly marked.
Snapshot updates are underline gains on regulation/form fixtures and one
empty spacer-column change in a subscripted header.
Corpus (508-doc public bench sweep): text output byte-identical on all
docs; underlined items +224/-0; strikeout now fires on redline docs.
Item-level GT coverage: is_underline 86->151/405, is_strikeout 0->10/44.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L3U6BKYCS73DVA83odAfYB