Skip to content

XML reader drops a section that has only a heading, so the provision after it loses its account and chapter headings #525

Description

@willhea

What's wrong

When a bill's XML gives a section a heading but no text, and puts the provision that heading names in the next element, DeltaTrack drops the heading. The provision then shows a breadcrumb that stops short, with no account name and no chapter name.

Some background, for anyone new to this:

  • The XML pipeline. DeltaTrack reads a bill either from its PDF or from the tagged XML that GPO publishes. This issue is in the XML reader, src/deltatrack/bill_tree.py. It turns the bill into a list of nodes, one per piece of provision text.
  • Breadcrumb (heading path). Each node carries the headings above it. display_path is the breadcrumb a reader sees on change cards, in the sidebar and as headings in the Full bill view, e.g. TITLE VII › Agriculture › Office of the Secretary. match_path is a lower-cased twin that the diff engine uses to pair a provision in one version with the same provision in the other.
  • Appropriations elements. GPO tags spending text with <appropriations-major>, <appropriations-intermediate> and <appropriations-small>, roughly the department, agency and account (the named fund) levels. "Intermediate" is just the middle tag. The reader keeps one "current major" and one "current intermediate" heading as it walks.

Example

116-hr-133 (Consolidated Appropriations Act, 2021), Division N. Sec. 751 is tagged as a <section> holding only its number and the heading "Office of the Secretary". Its next sibling is an <appropriations-intermediate> with no heading, whose text appropriates $11,187,500,000 "for the Office of the Secretary". The report shows no dollar amounts (#671, which removed financial data from reports); the figure is only how to find the provision.

A synthetic copy of that chapter, run on develop (d3935ee, checked 2026-10-05), with the chapter heading "Agriculture programs":

AI1  header=''  display_path=('TITLE VII—NUTRITION AND AGRICULTURE RELIEF', 'Agriculture')
S752 display_path=('TITLE VII—NUTRITION AND AGRICULTURE RELIEF', 'Agriculture', 'sec. 752')

Neither "Office of the Secretary" nor "Agriculture programs" appears in either path, or anywhere in the Full bill view text.

Why it matters

A reader sees the provision under "Agriculture" alone, on its change card and in the Full bill view, and has to read the sentence to learn what it funds. Nothing looks broken, so nobody notices.

CI can't see it. No committed XML file has this shape: of the 58 under tests/corpus/, none has a header-only section, and no subtitle, part or chapter mixes sections with appropriations elements (scanned 2026-10-05).

Cause

Two separate steps in src/deltatrack/bill_tree.py:

  1. The section is dropped. In _process_section_element, a section with no body and no subsections emits no node (if body_text or sub_specs:, line 950). Its heading isn't handed on either: _walk_structural_children clears pending_header on every section (line 1016). The hand-on that An account whose name and money sit in separate elements loses its name and files its money under its parent agency #474 added (a header-only element names the untitled one after it, in _process_appro_element, line 669) works only between appropriations elements. Tagged as an appropriations element instead, the same heading is kept.
  2. The chapter heading is overwritten. The untitled element sets the "current intermediate" heading to an empty string (current_intermediate = header, line 739). That erases the chapter's heading for this node and for every section after it in the chapter.

Done when

  • A test in tests/test_bill_tree.py builds this chapter shape. It asserts that the appropriations node's header_text is "Office of the Secretary" and that its display_path keeps the chapter heading and ends with the account. It fails on develop.
  • Sections after the account keep the chapter heading, and do not gain the account name in match_path. Reusing the An account whose name and money sit in separate elements loses its name and files its money under its parent agency #474 hand-on as-is would add it: in the control run, sec. 752's match_path gained office of the secretary.
  • The Full bill view prints "Office of the Secretary" above the provision's text.
  • The fast suite and uv run pytest -m slow --deselect tests/test_govinfo_corpus_parity.py pass with no pinned baseline changed. No committed file has this shape, so a moved pin means the fix reached further than intended.
  • If you can fetch 116-hr-133, run the section-coverage gate with CORPUS_SWEEP=1 (which sweeps every bill you have locally, not just the committed set). Post the output.

Scope

Where to start

Unverified

  • The real bill wasn't re-run today: govinfo wasn't reachable from the checking environment. The original report (2026-08-04, at a20d8b5) found Sec. 751 reaching no node in both the engrossed-amendment and enrolled versions.
  • The real chapter's heading, and whether its sections 752–756 lose it as the synthetic sec. 752 does.
  • How common the shape is outside 116-hr-133.

Activity

  1. changed the title [-]An $11.19 billion appropriation loses its account heading when a chapter mixes a section with an appropriations element[/-] [+]XML reader drops a section that has only a heading, so the provision after it loses its account and chapter headings[/+] on Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions