fix(tables): reject layout bands in the cell-rect fallback - #460
Open
flowjzh wants to merge 1 commit into
Open
Conversation
A template content band (one rect drawn repeatedly, no interior y-edges) plus header chips lets the stripe fallback serialize a whole text page as a table: the band's flowing prose lands in one giant row and reading order is destroyed. The existing paragraph-wall guard only fires under 4 non-empty rows, and the header chips supply those rows. Add has_dominant_prose_row, the row-granular sibling of has_dominant_prose_cell: reject when one row holds more than 500 chars and at least half the region's text. Per-cell signals stay blind here because the columns carve the prose into sub-threshold cells; only the row sum sees it. Regenerate the td9264 snapshot: the band-row pseudo-table at the document head now extracts as flowing text. A second pseudo-table further down (prose wrapped into rows by the body-font heuristic pass) is a separate pre-existing issue and is unchanged.
There was a problem hiding this comment.
No issues found across 5 files
Shadow auto-approve: would auto-approve. Focused parser bug fix: adds a dominant-prose-row guard to the cell-rect fallback so layout-band rects aren't serialized as tables, with unit and snapshot tests pinning the corrected extraction and no public/security/rollout tradeoffs.
Re-trigger cubic
flowjzh
force-pushed
the
fix/layout-band-stripe-fallback
branch
from
August 24, 2026 15:36
ed5ed6c to
064e0d2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resume- and form-template PDFs commonly carry decorative fill rects: a
page background, a full-content-band rect drawn several times (the
template's page frame, no interior y-edges), and a few header chips.
None of them are table borders, but the cell-rect fallback
(
detect_row_stripe_table_from_cell_rects) serializes the whole pageas a markdown table:
y-edges, so the entire page body lands in one table row;
x position into pseudo-cells;
The reading order of the document is destroyed.
Why the existing guards miss it
The full-grid pass correctly rejects the cluster (sparse content — it
knows this is not a data table), but the fallback re-accepts it on cell
density. The fallback's paragraph-wall guard
(
max_cell_len > 500 && non_empty_rows < 4) is bypassed whenever theheader chips above the band contribute 4 non-empty rows — exactly the
layout these templates have.
The fix
Add
has_dominant_prose_row, the row-granular sibling of the existinghas_dominant_prose_cellhelper (which the other rect-detection pathsalready call): after cell assignment, reject the table when one row
holds more than 500 chars and at least half the region's text.
Genuine stripe tables spread their items across rows; a rect band
boxing flowing prose concentrates it in one row. The signal has to be
row-granular: the columns carved from the band split the prose into
sub-threshold cells, so every per-cell check stays blind.
Repro
tests/fixtures/template_layout_band.pdf(new, synthetic, PII-free):2 page backgrounds + 3 header-chip rows + one content-band rect drawn
4 times + ordinary resume-shaped text inside the band.
Before: