Repository navigation
PDF report shows a false "Moved" card when only a heading's line wrap changed #648
Description
Re-scoped 2026-10-07 (comment).
- Cause 2 below is fixed by Decide a move's kind in the differ, by one rule on both pipelines #820: no card whose label isn't
SEC. nreads "Renumbered" any more.- Cause 1 remains: 18 wrap fragments, such as
NAVY AND MARINE CORPS → AND MARINE CORPS, are nowrelocated, so they show a false "Moved" card instead.- Done when, first item, now reads: no moved card at all for a heading whose printed text is the same in both versions.
- Still blocked on Recover PDF heading structure for the bill ledger, measured by agreement with the XML twin #734. The original text follows unchanged.
What's wrong
In a PDF comparison, the report can say a heading was "Renumbered" when the heading is printed identically in both versions and only its line break moved.
Some background, for anyone new to this:
- PDF pipeline. DeltaTrack can compare two printed PDFs of a bill. The PDF reader infers headings and sections from the print.
- Anchors. An anchor is the label the PDF reader records where a section or heading starts, taken from the printed heading text.
- Change cards and moved cards. The report lists each change as a card. When the two versions' text is matched but sits in a different place, the card is "moved". The card then reads either
Moved: <old breadcrumb> → <new breadcrumb>orRenumbered: <old label> → <new label>. - Canonical diff. This is the JSON both pipelines produce (
schema/canonical-diff.md). There,move.kindisrenumberedwhen "the section's anchor identifier changed", andrelocatedotherwise.
Example (checked 2026-10-05 on develop, d3935ee)
118-hr-4366 (FY2024 appropriations), Senate calendar print (v3) → Senate amendment (v4). Both print FAMILY HOUSING OPERATION AND MAINTENANCE, NAVY AND MARINE CORPS, wrapped differently:
- v3, p. 10:
FAMILY HOUSING OPERATION AND MAINTENANCE,/NAVY AND MARINE CORPS - v4, p. 15:
FAMILY HOUSING OPERATION AND MAINTENANCE, NAVY/AND MARINE CORPS
The report says Renumbered: NAVY AND MARINE CORPS → AND MARINE CORPS. The same pair also reports Renumbered: ARMY → FAMILY HOUSING OPERATION AND MAINTENANCE, ARMY.
Reproduce (about 5 seconds):
uv run ./diff_pdf.py tests/corpus/118-hr-4366/3_placed-on-calendar-senate.pdf \
tests/corpus/118-hr-4366/4_engrossed-amendment-senate.pdf --format json -o out.jsonAcross the 17 PDF pairs the product accepts, develop produces:
- 161 moved cards, 153 of them "Renumbered".
- 130 of those are
SEC. n → SEC. m. Not checked one by one; most are likely genuine. - 23 are heading labels. Most are fragments of a wrapped heading:
FACILITIES → STATE EXTENDED CARE FACILITIES,POWER ADMINISTRATION → ADMINISTRATION,DEBT → FEDERAL DEBT. Three were checked against the printed page lines, and all three are wrap-only. - Of those 23, 3 look like genuine heading edits:
ENERGY SECURITY → ENERGY SECRUITY,RELATED AGENCY → RELATED AGENCIESandADMINISTRATIVE PROVISION → PROVISIONS.
Why it matters
A staffer is told that a provision was renamed or renumbered when it wasn't. That is a false statement in the part of the report meant to say what changed, and it looks the same as a real one. The pairs where it happens are re-typeset amendments, which are exactly the comparisons staff run.
Cause
There are two places:
- The PDF reader takes a heading from one printed line. A wrapped heading becomes a fragment that depends on where the line broke. This is the same root as In PDFs, a long account name that wraps onto a second line shows up as a fake agency plus a fragment account #524 (a wrapped account heading read as an agency plus an account) and Reading a bill from PDF, headings printed across more than one line get the wrong name or parent #732 (headings spanning more than one printed line are misread). Recover PDF heading structure for the bill ledger, measured by agreement with the XML twin #734 (the open PR that rewrites PDF heading detection) addresses it.
_pdf_movelabels any text difference "renumbered". It is insrc/deltatrack/formatters/canonical.py:262-274, and_move_info_html(lines 521-536) prints it. It compares raw anchor text: any difference becomes "renumbered", including a heading edit, which is not a renumbering. Recover PDF heading structure for the bill ledger, measured by agreement with the XML twin #734 doesn't touch it.
Where #734 leaves this (checked 2026-10-05, #734 head e3d3926)
The same census gives 144 moved cards and 137 "Renumbered": the same 130 SEC. cards and 7 heading labels.
- Gone: every wrap-only fragment above, including
NAVY AND MARINE CORPS. The 2026-09-28 comment on this issue said that case was not fixed; it predates Recover PDF heading structure for the bill ledger, measured by agreement with the XML twin #734's last commits. - Kept, correctly: the 4 genuine renumberings in 115-hr-5895 (
SEC. 103 → SEC. 102,104 → 103,105 → 104,107 → 105), and the 3 heading edits above. - Still doubtful, and not about wrapping:
ELECTRICITY DELIVERY → NUCLEAR ENERGYandSEC. 5 → PROHIBITION ON USE OF FUNDS, both also ondevelop. They look like two different sections paired together.- a new crossed pair in 115-hr-5895:
DEPARTMENT OF DEFENSE FAMILY HOUSING IMPROVEMENT FUND → MILITARY UNACCOMPANIED HOUSING IMPROVEMENT FUND, and the reverse.
Done when
- On 115-hr-5895 and 118-hr-4366, no "Renumbered" card appears for a heading whose printed text is the same in both versions. (Holds since Decide a move's kind in the differ, by one rule on both pipelines #820. Now: no moved card at all for such a heading.)
- The genuine
SEC.renumberings in 115-hr-5895 are still reported. - The genuine heading edits (
SECRUITY,AGENCY → AGENCIES) are still reported as changes. - A test pins these cases. The suite passes today with the defect present, so a passing suite is not proof.
- The PDF canonical baseline (
tests/data/pdf_canonical_baseline.json) is regenerated on purpose, and its diff is reviewed row by row.
Scope
- In scope: false moved cards caused by line wrapping. (The
_pdf_movehalf, whether its raw-text comparison is still needed, was settled by Decide a move's kind in the differ, by one rule on both pipelines #820, which removed it.) - Out of scope:
- Assembling wrapped headings itself: Reading a bill from PDF, headings printed across more than one line get the wrong name or parent #732 and In PDFs, a long account name that wraps onto a second line shows up as a fake agency plus a fragment account #524, which Recover PDF heading structure for the bill ledger, measured by agreement with the XML twin #734 would close.
- What
moved,renumberedandrelocatedshould mean, under ADR 0006 (the canonical diff contract). - The crossed pairs and other correspondence errors. These may need their own issue.
Where to start
- Blocked on Recover PDF heading structure for the bill ledger, measured by agreement with the XML twin #734. It is open, not a draft, with changes requested on 2026-09-30. The author pushed fixes the same day, and it awaits re-review. It conflicts with
develop. Re-scope this issue after it merges. - Useful now:
- Reproduce the example above.
- Read
docs/research/pdf-matching-convergence/moved-semantics.md. - Run the census on
developand on Recover PDF heading structure for the bill ledger, measured by agreement with the XML twin #734's branch:uv run python docs/research/pdf-matching-convergence/probes/pdf_move_user_facing.py. It takes about 80 s and writesdocs/research/pdf-matching-convergence/results/move-user-facing.json.
- Code and tests:
src/deltatrack/move_kind.py(since Decide a move's kind in the differ, by one rule on both pipelines #820), and_move_info_htmlinsrc/deltatrack/formatters/canonical.py, andtests/test_formatters_adapters_pdf.py.
Unverified
- Whether the 130
SEC.renumberings are all genuine. - Whether wrapping also affects the table of contents or the Full bill view. Only change cards were measured.
- Bills outside the committed corpus.
History
The first measurement, at d5a1ad0, found 156 of 165 moved cards reading "Renumbered". The 2026-09-28 comment on this issue measured #734 at 156 → 143 against develop at c636448. The 2026-10-05 counts above were taken before #820; the 2026-10-07 comment has the counts after it.
Activity
mattzamora commentedon Sep 28, 2026
#734 fixes wrapped-heading assembly in the parser (#732, a PDF heading whose structure spans more than one printed line is misread). As this issue asks, here is the consequence checked rather than assumed, over the 17 production-accepted adjacent pairs of the committed corpus,
developatc636448against the branch:Renumbered: X -> Y: 156 → 143.GINIA.— -> WEST VIRGINIA.—,ARMY -> FAMILY HOUSING OPERATION AND MAINTENANCE, ARMY,TRATION -> MAINTENANCE, WESTERN AREA POWER ADMINISTRATION,DEBT -> FEDERAL DEBT,FACILITIES -> STATE EXTENDED CARE FACILITIES.SEC. 103 -> SEC. 102,SEC. 104 -> SEC. 103,SEC. 105 -> SEC. 104,SEC. 107 -> SEC. 105) and the heading edit where the new version is misspelled (…ENERGY SECURITY… -> …ENERGY SECRUITY…).FAMILY HOUSING OPERATION AND MAINTENANCE, NAVY AND MARINE CORPS, in both 115-hr-5895 and 118-hr-4366. The old side now reads the whole name, but the Senate strike-all print still yieldsAND MARINE CORPSon its own, so the card now readsFAMILY HOUSING OPERATION AND MAINTENANCE, NAVY AND MARINE CORPS -> AND MARINE CORPS.SECURITY INVESTMENT PROGRAM -> NORTH ATLANTIC TREATY ORGANIZATION SECURITY INVESTMENT PROGRAM): the same root cause in a milder form.formatters/canonical._pdf_move, is untouched.So #734 advances this issue rather than closing it.
docs(scratch): map audit findings to #653 and existing issues
[-]PDF diff reports sections as renamed when only the line wrapping changed[/-][+]PDF report says a heading was "Renumbered" when only its line wrap changed[/+]Notes: status after the five follow-ups, and the next plan
willhea commentedon Oct 7, 2026
Update after #820 (move kind decided by the differ, merged 2026-10-07), and re-scope. Measured on
developat7076771, over the 17 PDF pairs production accepts.Cause 2 is fixed.
_pdf_move's raw-text comparison is gone.move.kindnow comes from the differ (move_kind.py), which calls a moverenumberedonly when a section number changed.renumbered, 17relocated_and_renumbered, 31relocated.SEC. nisrenumberedany more (was 23). So no card reads "Renumbered: NAVY AND MARINE CORPS → AND MARINE CORPS".Cause 1 is not, and it now shows up as a false "Moved" card. The wrap fragments are
relocatedinstead ofrenumbered. The card still says a provision moved when it was only printed with a different line break. 30 moved cards have a label that is notSEC. non at least one side:NAVY AND MARINE CORPS → AND MARINE CORPSandARMY → FAMILY HOUSING OPERATION AND MAINTENANCE, ARMY(both in 115-hr-5895 and 118-hr-4366 v3→v4),DEBT → FEDERAL DEBT,POWER ADMINISTRATION → ADMINISTRATION,FACILITIES → STATE EXTENDED CARE FACILITIES,HOUSING IMPROVEMENT FUND → FUND,ACTIVITIES → LEGAL ACTIVITIESENERGY SECURITY → ENERGY SECRUITY,RELATED AGENCY → RELATED AGENCIES,ADMINISTRATIVE PROVISION → PROVISIONS(a) IN GENERAL×3,SALARIES AND EXPENSES,DEPARTMENTAL ADMINISTRATION,CAPITAL CONSTRUCTION AND OPERATIONS,STATE OF MISSISSIPPI.—ELECTRICITY DELIVERY → NUCLEAR ENERGY,SEC. 5 → PROHIBITION ON USE OF FUNDSThe 18 fragments are the reading of a heading from one printed line, which #734 rewrites. It measured every wrap-only fragment gone on 2026-10-05 (its head
e3d3926), apart from the strike-all print'sAND MARINE CORPS, per the comment above. #734 still awaits re-review, and its base (c636448) is behinddevelopby #800–#827.Re-scope. Title changed to name what's left: a false "Moved" card from a wrapped heading. What changes in the "Done when" list:
_pdf_movehalf of "In scope" is done.SEC.renumberings in 115-hr-5895 stay reported, the 3 heading edits stay reported, and there's a test and a reviewed PDF-baseline regeneration.This stays blocked on #734. The 2 doubtful pairings remain out of scope here.
To reproduce the table: run
compare_pdfsover the accepted keys oftests/data/pdf_canonical_baseline.json, and list the changes with amovewhose last path label on either side doesn't start withSEC.Generated by Claude Code
[-]PDF report says a heading was "Renumbered" when only its line wrap changed[/-][+]PDF report shows a false "Moved" card when only a heading's line wrap changed[/+]