A table keeps its headings, its sections and its caption - #744
Conversation
|
The four NVDA documents, re-extracted under this branch and judged by the same second model as #743 (numbers in brackets are #743 on the same documents):
Split by where the quote comes from: the 432 statements taken from table rows are misworded 1%, not stated 0%, reads alone = false 16%; the 398 from prose are misworded 4%, not stated 1%, reads alone = false 5%. Under #743 the 192 table-row statements were misworded 21% and unreadable 31%. What the judge still calls unreadable on table rows is one shape, the cash-flow lines "NVIDIA —Changes in operating assets and liabilities, net of acquisitions › Accounts receivable→ (24,590) [Six Months Ended July 26, 2026]", where the section path carries the meaning (a change, not a balance) and the judge reads it as a fragment. The 8-K of 2026-09-02 counts fewer statements because its cover-page boilerplate is shared with the other two 8-Ks and dedup attributes those statements to the first document that stated them; per chunk it yields 102, as before. Drops: 🤖 Generated with Claude Code |
df861f5 to
977b619
Compare
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: WaylandYang <wayland0916@gmail.com>
31d4112 to
4f5953a
Compare
On the branch of #743, after it. Under #743 the NVDA earnings release got worse (misworded 10% → 19%, reads-alone 15% → 22%), and 38 of its 56 misworded statements were table rows of the shape "Basic —three months ended→ $1.08". The cause was not the contract: between the HTML converter and the chunker the tables lost their column headings, so every piece carried a fake header (
| NVIDIA CORPORATION | | |) and none of the real ones. This change moves table handling to the reader, where the structure still exists.What lands
A table is rendered from the DOM (
utopia_ingest::table, before the Markdown converter sees it), by structure alone: hidden cells are skipped, spanning cells are laid on a grid, columns empty in every row go, a currency symbol or bracket in its own cell rejoins the number beside it (a dash that means "nil" stays where it is). Rows are classified by what they hold: a lone cell before any header or data is a caption line, a row of words with no label column is a header row, a lone label after the headers is a section, a label followed by figures is data. Multi-row headers stack into one heading per column ("Three Months Ended July 26, 2026"); sections fold into the labels of the rows under them ("Current assets › Accounts receivable, net", "Net income per share › Basic"), with indentation read from leading empty cells or the label's padding, and a section ends at a row of its own depth only once it has had a deeper child; a table split by a page break into a headerless second<table>with the same column count takes the headings of the one before; caption lines become a paragraph before the table. Nested tables and the tables of other parsers keep the converter's path.The chunker keeps the caption run. Up to five consecutive short paragraphs before a table are its caption ("NVIDIA CORPORATION", "CONDENSED CONSOLIDATED STATEMENTS OF INCOME", "(In millions)", "(Unaudited)"), so every piece of a split table names the report, the unit and the periods.
The contract says what a period column is. In a table a cell is a statement about its row's thing whose phrase is the column heading; when the heading names one time it is
wheninstead, the statement is about the thing the caption names and the phrase is the row label with its path; a heading that names a change between periods (quarter over quarter, year over year) stays the phrase; a unit the caption gives is a qualifier.A table row takes its period from the header in the same chunk. The time-in-quote check kept 40 periods out of the release because the heading is not in the row's own quote; a quote that is a table row now finds its time words anywhere in the chunk, which by construction holds the table's header.
Two counted shapes.
phrase_is_valueandphrase_is_subjectrecord a statement whose phrase repeats its value or its subject, the two shapes a model writes for a row without a heading or a caption. The statement is kept: the subject and the value are there, so nothing is lost, and the count makes the shape measurable.Verified
Unit tests on the renderer (filing table with two header rows, spacer columns, dollar cells, sections and totals; a lone label as caption; a first row of words as header; hidden cells; dashes; a continued table; nested tables left alone), on the caption run in the chunker, and on time location for table rows; 84 ingest tests, clippy clean.
On the real release: 52 chunks become 32, none a table without its header; the balance sheet, income statement and cash-flow statement render with their real headings and section paths; the 8-K vote tables are unchanged. First statements from the highlights table under the final wording:
The four NVDA documents are being re-extracted and judged under this build; the numbers against #743 follow in a comment.
Not in this change
Tables from the DOCX, PDF, spreadsheet and CSV parsers (they still promote the first row); the NVDA cross-domain paragraph units, which were cut from the old chunks and have no headings, and their reference facts, which carry no period; a bench check that a cell statement under a period column carries
when; the "Total" row of a section without deeper children, which lands in the last sub-section.🤖 Generated with Claude Code