Parsing the Congressional Record Ain't Easy

A field report on the cases that broke our pipeline.

One of our primary goals is that a reader can get to a congressional member's substantive statement without first wading through procedural content present in the Congressional Record, such as quorum calls, yields, and motions. If that content stays in, the reader has to pick the statement out of it.

To do that, we run the Congressional Record through a processing pipeline that relies on formatting rules maintained by the Government Publishing Office (GPO). In practice, however, the Record's source files are not always consistent. Headings are usually uppercase but may appear in lowercase, typos get introduced, and rare long-tail cases turn up (for example, correction NOTE blocks that appear in only a handful of statements a year). We make mistakes on our side too, whether missing a formatting case or implementing a rule wrong. When either side fails, what we store is not what the member said. A statement can end before the member finished, contain administrative data we aim to remove, or treat a topic heading as spoken dialogue.

This post is a field report on the cases that broke our pipeline, and how we fixed them. By the time we wrote this, we had already processed several years of the Congressional Record (2024 through 2026), hoping to surface corner cases like the ones below before they piled up in production. The original plan was straightforward: fix whatever rule was wrong, then patch the affected records in our database by hand. That plan broke down quickly. A combination of GPO layout quirks and our own processing mistakes turned up enough issues across enough statements that we felt more comfortable reprocessing the years in full.

These issues included opening and closing sentences cut off during cleaning, one speech stored as several statements, several speeches stored as a single statement, topic headings stored as statement text, GPO editorial notes left in the speech text, legislation incorrectly linked to statements, and Extensions-of-Remarks tributes attributed to the wrong member or dropped when GPO’s bylines and headers did not match our expected patterns.

50K Statements scanned
474 Session days with trimmed text
1,039 Same member and topic, split into separate statements
145 Headings in statement text
12 NOTE blocks in statement text
160 Statements under wrong titles
What our investigation of 2024 through 2026 turned up

Each of these issues is discussed in detail below. For every case we describe how our original processing worked, the failure it produced, and the change we made to fix it.

Case 1: One speech stored as two statements

All of these cases have the same symptom: one continuous floor speech stored as two statements. The causes differ, and are discussed below.

Case 1a: One speech stored as two statements with different titles

We were labeling Senate statements for a fine-tuning dataset when we noticed a statement from Senator Jeff Merkley that opened without the traditional address to the chair, "Mr. President." This is somewhat rare, as the GPO generally publishes speeches with the address to the chair even if the oral statement does not begin with it. We decided to investigate this case in more detail.

The statement text turned out not to be a stand-alone statement at all, but the second half of a single floor statement by Merkley that had been incorrectly recorded as two distinct statements.

In our database, that one speech appeared as two records with different titles. In GPO’s source, the opening and the continuation were published as separate chunks, with nominations and confirmations in between. The excerpt below shows how those pieces fit together in the Record; after it, each half as we had stored it.

As published in the Congressional Record Titles bolded for clarity; they are not bolded in the source file.
                    TRUMP ADMINISTRATION
  Mr. MERKLEY. Mr. President, I have come to the Senate floor tonight
to ring the alarm bells. We are in the most perilous moment, the biggest
threat to our Republic since the Civil War. President Trump is shredding
our Constitution.
  Is it OK for masked Federal agents to arrest people off the streets
because of their skin color or their accent? No way, not in a free America.
# … speech continues …


# … unrelated administrative pages: nominations and confirmations …


              TRUMP ADMINISTRATION--(Continued)
  Mr. MERKLEY. It is about Paul Revere’s ride in April 1775, as he
sounded the alarm about military troops marching on American cities; one
lantern if the British were attacking by land and two lanterns if they were
attacking by sea. He rang the alarm bells so that the American colonists
could respond and save their Colonies, just as I am attempting to ring
alarm bells to say that we here in the Senate and in the House have to
respond and save our Republic.
# … speech continues …
Stored as Statement 1
Unrelated administrative pages
Stored as Statement 2

Each statement, as we had stored it:

Statement 1
Trump Administration

Mr. President, I have come to the Senate floor tonight to ring the alarm bells. We are in the most perilous moment, the biggest threat to our Republic since the Civil War. President Trump is shredding our Constitution.

Is it OK for masked Federal agents to arrest people off the streets because of their skin color or their accent? No way, not in a free America.

… speech continues …

Statement 2
Warning Signs of Democratic Backsliding

It is about Paul Revere’s ride in April 1775, as he sounded the alarm about military troops marching on American cities; one lantern if the British were attacking by land and two lanterns if they were attacking by sea. He rang the alarm bells so that the American colonists could respond and save their Colonies, just as I am attempting to ring alarm bells to say that we here in the Senate and in the House have to respond and save our Republic.

… speech continues …

As discussed in our previous post on speaker identification, GPO publishes the Congressional Record as HTML files split by printed page and topic—roughly 140 on a typical session day. Merkley’s speech ran across several of them. That is normal; when a member’s remarks continue on the next consecutive file, our pipeline carries the active speaker and topic forward and appends the text to the same statement. In this case, three things went wrong:

  1. Unrelated pages sat between the two speech chunks. After Merkley's first chunk ended, GPO inserted several pages of nominations and confirmations before his speech continued. Our merge logic only stitched across consecutive speech files. Those administrative pages broke the chain.
  2. We didn't respect GPO's continuation heading. When a speech picks up on the next page, GPO often does not mark it at all—the text simply continues. We had already built in processing for this case in our previous version of the pipeline. Importantly though, that carryover only works when the speech resumes on the very next file. However, sometimes GPO adds a “Continued” annotation to the title, as in TRUMP ADMINISTRATION--(Continued). That is GPO's way of saying “same topic, same speaker, pick up where the last file of that statement left off.” Continued markers often appear when administrative content sits between the first and second parts of a Congressmember's statement—precisely the case that broke our consecutive-file carryover logic. We inadvertently ignored this important --(Continued) suffix in our previous parsing logic. In Merkley's case, GPO had inserted nominations and confirmations between the two parts of his statement. That oversight meant his statement failed to parse correctly, as did many other statements we found subsequently.

    GPO attaches the suffix directly to the title with no space (TRUMP ADMINISTRATION--(Continued)). Split on spaces, the line is two tokens: TRUMP and ADMINISTRATION--(Continued). In our original flow, before checking whether either token “looked like” a heading, the detector stripped all punctuation from each one—dashes, parentheses, and all. On the second token that leaves a single fused word: ADMINISTRATIONContinued, with no boundary between the title and Continued. To decide whether the line was a heading at all, our detector then measured how uppercase it looked: it counted as a title only if at least 80% of its letters were capitals. That cutoff existed to separate real headings from ordinary sentences and was tuned while constructing the initial pipeline processing. The threshold worked well in almost all cases, but occasionally fell into error states like this one. Because we never stripped the suffix in title pre-processing, the lowercase letters in Continued stayed fused onto the title word and pulled the uppercase ratio down to about 71%, just under the line.

    Since the heading was rejected by title check, when Merkley’s speech resumed the second part was detected as a new statement with no title. In these cases we intentionally mark statements as UNTITLED.

  3. Our title-assign step filled in UNTITLED. For the rare topics where parsing leaves no detected title, a later pipeline step reads the speech text and asks an LLM to assign one. Here it produced Warning Signs of Democratic Backsliding. That title no longer matched Trump Administration from the opening statement, so the continuation was stored as a separate statement.

Here is the file order GPO published that day, and what our merge logic did with it:

What GPO published vs. what we stored
Merkley's speech, part 1
Title: Trump Administration
Stored as Statement 1
then
Nominations & confirmations
Unrelated administrative pages
Merge chain breaks here
then
Merkley's speech, part 2
Title: Trump Administration--(Continued)
LLM-generated title: Warning Signs of Democratic Backsliding
Trump Administration--(Continued) wasn’t recognized as a title, so it could not be stitched back to the first part of Merkley’s statement, Trump Administration. Processing logic therefore treated Part 2 of Merkley’s statement as a new statement with no title. The title-assignment step in the pipeline passed the untitled section to an LLM for titling. Merkley’s single statement ended up marked as two statements with different titles.
Stored as Statement 2
Speech chunk
Merge chain breaks
Should have stayed one statement

It is worth noting that none of this is an error on GPO's side. It is driven by our goal of parsing and cleaning the Congressional Record to an almost maniacal degree—not loading GPO's page files into a database as-is, but deciding which chunks are one statement, which are boilerplate, which titles belong together, and stitching a single floor speech back into one statement when GPO spread it across files with admin pages in between.

The fix

We made two parser changes:

  1. Recognize --(Continued) headings. A line like TRUMP ADMINISTRATION--(Continued) now parses as the same topic as TRUMP ADMINISTRATION, not a new title and not UNTITLED.
  2. Carry the topic across admin-only gaps. When the same speaker resumes under a continued title, we now append to the prior statement even when unrelated admin page-files sit in between.

Case 1b: One speech stored as two statements when a document is introduced mid-speech

On the floor, members often submit letters, reports, or other documents into the Congressional Record in order to provide supporting evidence for their statement. Our processing separates out these submitted documents as what we call “artifacts” so that in our Browse UI on Second Congress we can present these written artifacts as separate supplementary material to the core spoken statement.

While we correctly processed statements in which documents are introduced into the Record at the end of a speech, we found a bug in the way we process statements that have documents introduced in the middle of a speech. This bug was discovered as part of our audit in Case 1a when we were investigating all instances of a single speaker having two consecutive statements that were unmerged in our database.

As discussed in our previous post on speaker identification, we treat every speaker byline as the start of a new statement. As a reminder, a speaker byline is an annotation the Congressional Record inserts to identify who has the floor—such as Mr. SMITH of Missouri. When a member introduces a document into the Record in the middle of a speech and then continues speaking, the Record reprints the same speaker’s byline before their remarks continue. Because we cue new statements based on this byline, this printing convention of the Congressional Record caused our processing to erroneously record a new statement by the same speaker.

One example is a speech by Representative Jason Smith on January 18, 2024, during debate on the Supporting Pregnant and Parenting Women and Families Act:

As published in the Congressional Record
  Mr. SMITH of Missouri. Mr. Speaker, last year, Missouri provided $6.3
million in TANF funding to pregnancy resource centers. This funding is
provided for mothers and fathers for nonmedical support, such as baby
clothes and formula, and support for families until the age of 1.
  Mr. Speaker, I include in the Record a letter from the Missouri
Department of Social Services to the Administration for Children and
Families opposing any restrictions on using TANF for these critical
services.

  Missouri Department of Social Services
  November 30, 2023.

  Re Strengthening Temporary Assistance for Needy Families (TANF)
  as a Safety Net and Work Program (RIN 0970-AC99).

  To Whom it May Concern: The Missouri Department of Social Services
  (DSS) has reviewed in detail the Notice of Public Rulemaking (NPRM),
  RIN 0970-AC99, issued by the Administration for Children and
  Families (ACF) on October 2, 2023. Below, please find DSS' comments
  on the proposed rule.

# … letter continues …

  Sincerely,
  Robert J. Knodell, Director.

  Mr. SMITH of Missouri. Mr. Speaker, at least four other States--
Indiana, Louisiana, Ohio, and Pennsylvania--provide TANF funding to
pregnancy resource centers, which meets the TANF purposes of assisting
needy families and reducing dependence on government.
  As Missouri's comment letter states, it is imperative that we protect
this funding and the vital services pregnancy resource centers provide
for our families and communities.
  Mr. Speaker, I reserve the balance of my time.

This one speech appeared in our database as two separate statements under the same title. The first row held the opening spoken segment and the Missouri DSS letter as an attached artifact; the second row held only the resumed speech after the insert.

What we stored in our database — first row
Supporting Pregnant and Parenting Women and Families Act

Mr. Speaker, last year, Missouri provided $6.3 million in TANF funding to pregnancy resource centers. This funding is provided for mothers and fathers for nonmedical support, such as baby clothes and formula, and support for families until the age of 1.

I include in the Record a letter from the Missouri Department of Social Services to the Administration for Children and Families opposing any restrictions on using TANF for these critical services.

What we stored in our database — second row
Supporting Pregnant and Parenting Women and Families Act

Mr. Speaker, at least four other States—Indiana, Louisiana, Ohio, and Pennsylvania—provide TANF funding to pregnancy resource centers, which meets the TANF purposes of assisting needy families and reducing dependence on government.

As Missouri’s comment letter states, it is imperative that we protect this funding and the vital services pregnancy resource centers provide for our families and communities.

Mr. Speaker, I reserve the balance of my time.

The fix

We fixed this by updating our processing to merge consecutive statements by the same member when an inserted document sits between them as an artifact on the first row. Artifact extraction was already correct; the missing step was rejoining the spoken halves into one statement.

Case 1c: One speech stored as two statements when duplicate copies are published in the Record

While auditing Case 1, we found duplicate statement text in the database. Tracing one example back to the Congressional Record source showed the speech in two separate source files. We do not know whether that republication is an error or intentional, and we could not find a rule that explains when GPO republishes text this way.

Nearly all of the duplicate pairs we found in a scan of our 2024–2026 statements came from bill introductions. In those cases, a statement first appears under the Senate section heading for introduced bills, then appears again in full under the bill’s formal title. About 65% of bill-introduction speeches in our 2024–2026 dataset are republished this way, but the rest are not. We also saw a handful of cases elsewhere, in House tributes in Extensions of Remarks, and in Senate amendment text.

One example is Senator Jack Reed on May 20, 2026, introducing a bill to align Job Corps with the defense industrial base. Each span of printed pages in the Record has a corresponding HTML source file—in this case, CREC-2026-05-20-pt1-PgS2417.htm and CREC-2026-05-20-pt1-PgS2418.htm. Reed’s spoken remarks appear in full in both files:

CREC-2026-05-20-pt1-PgS2417.htm
  Mr. REED. Mr. President, we need to revitalize our Nation's
defense and maritime industrial bases, and we need to develop the
workforce to achieve this goal. Job Corps and registered apprenticeship
programs have the track record and capacity to support this effort.
# … speech continues …
CREC-2026-05-20-pt1-PgS2418.htm
  Mr. REED. Mr. President, we need to revitalize our Nation's
defense and maritime industrial bases, and we need to develop the
workforce to achieve this goal. Job Corps and registered apprenticeship
programs have the track record and capacity to support this effort.
# … identical speech continues …

Because of the duplication in the source files, we stored this speech twice with identical text but two different titles. These two titles reflect two different processing rules. The first statement is titled Statements on Introduced Bills and Joint Resolutions, from standard title detection on the section heading. The duplicate is titled A Bill to Provide for Alignment of the Job Corps With the Defense Industrial Base, and for Other Purposes. The second source file has no title assigned by the Record. When that happens and our legislation pipeline resolves exactly one bill for the statement, we use that bill’s name as the title. We describe that pipeline in Case 6 below.

The fix

We added a deduplication pass that drops a later statement when the chamber, member, and normalized text all match an earlier one and the speech is at least 10 words. The 10-word floor skips identical short procedural phrases—“I object,” “I yield back,” and the like—that a member may legitimately say more than once in the same day. There is no universal deduplication rule guaranteed to work; this cutoff may need further tuning, and duplicates are something we will have to monitor manually.

Case 1d: One speech stored as two statements when a line wrap mimics a presiding officer's byline

When a presiding officer speaks, GPO prints a byline like The PRESIDING OFFICER (Ms. Rosen). or The VICE PRESIDENT. Our detector for those bylines was compiled case-insensitively—a tolerance meant for variation in how the role is printed. The tolerance quietly extended to the word “The” itself, and that is where it went wrong: GPO wraps text at a fixed column, so when a member’s sentence merely mentions a presiding officer, the wrap can land that mention at the start of a physical line.

Senator John Cornyn, January 12, 2022, arguing against a filibuster carve-out. One continuous sentence of his speech, as wrapped in CREC-2022-01-12-pt1-PgS166.htm:

CREC-2022-01-12-pt1-PgS166.htm
ball to the Senate rules. They blow up the rules and pass this so-
called election bill with only 50 votes plus the tie-breaking vote of
the Vice President. They would likely spend the rest of the year
checking other items off of their radical wish list. This idea about a

Read case-insensitively, the third line is a perfect presiding-officer byline: “the” + a role + a period + trailing text. Our parser concluded the Vice President had begun speaking. It closed Cornyn’s statement mid-sentence—ending at “…plus the tie-breaking vote of”—and attributed the next 1,016 words of his speech to a new speaker, The Vice President. Because a presiding officer’s turns are administrative, those 1,016 words were then excluded from the database entirely. No validation caught it: page-level coverage saw all the words present, just mislabeled, and the misattributed block reads as perfectly plausible English.

The fix

A genuine byline always capitalizes “The”; a wrapped mention mid-sentence never does. We scanned every line in 33,696 source files that matched the case-insensitive pattern: 4,766 matches, of which 4,762 begin with a capital “The” and are genuine bylines. The remaining four—all lowercase—are all this defect: the Cornyn split, a recess announcement severed at “the Chair.” the same day, and two more instances in November 2023 nobody had noticed. The detector now requires the literal capital “The” while keeping the role name itself case-tolerant.

Re-parsing every source file we hold with the old and new detectors side by side: 3,846 of 3,850 files identical, and the only four that changed are the four known false positives—1,117 words of member speech restored, zero words lost. Cornyn’s sentence reads whole again: “…with only 50 votes plus the tie-breaking vote of the Vice President. They would likely spend the rest of the year…”

Case 2: A speech dropped when one source file spans several printed pages

Case 1a described carryover: when GPO does not reprint a byline because the same member is still speaking, we carry the speaker forward from the previous source file. That carryover is gated on the two files being adjacent in the Record. We checked adjacency using the page number in the file name—and that number is only the page a file starts on.

Most source files print on a single page, so the starting page and the ending page are the same and the check is correct. But GPO regularly prints one file across several pages. When that happens, the next file starts several page numbers higher, our adjacency check reads the gap as a break in the sequence, and the carryover is refused. If that next file happens to open without a byline, there is no speaker to attach the text to and the speech is dropped.

Senator John Barrasso on January 11, 2022 is one example. CREC-2022-01-11-pt1-PgS143.htm is printed across pages S143–S146 and ends with him still speaking:

CREC-2022-01-11-pt1-PgS143.htm
# … speech continues …
those are and why what the Democrats are proposing now is in the wrong
direction for the country.
  So I believe it is misguided, and I concur with her comments.

The next file picks him up under a fresh section heading. GPO prints the heading but not the byline, because it is the same senator continuing:

CREC-2022-01-11-pt1-PgS146.htm
                             Nord Stream 2

  Mr. President, I come to the floor today on another matter, and that
is to support sanctions on Vladimir Putin and his Nord Stream 2
pipeline.
  This body will be voting on that very issue in the next day or so,
and I am urging my colleagues to support S. 3436, which is known as
Protecting Europe's Energy Security Implementation Act.
# … speech continues …

The two files are consecutive in the Record—the first ends on S146 and the second begins on S146. But the file names read PgS143 and PgS146, so our check saw a three-page jump and refused the carryover. All 1,420 words of the Nord Stream 2 speech were left with no speaker.

This is the same limitation described in Case 1a, reached by a different route. There, administrative pages sat between the two halves of the speech and broke the chain. Here nothing sits between them at all—the first file simply prints across more than one page, which is enough to make a genuine continuation look like a gap.

The fix

Each source file already records the printed pages it covers. For the file above, that span is S143–S146. We now judge adjacency against the last page of that span rather than the page in the file name. A file is treated as continuing the previous one when it begins anywhere inside that span, or on the page immediately after it. Files that print on a single page are unaffected, because for them the two values are identical.

Re-parsing every source file we still hold, the change recovered 48,911 words of floor speech across 433 files and removed nothing: no file lost a statement or lost text. Barrasso’s Nord Stream 2 remarks are restored in full, as are three other speeches in the same month—two by Senator Dan Sullivan and one by Senator Patrick Leahy. In almost every recovered file the section heading was already correct, since GPO reprints the heading on a continuation page even when it omits the byline; it was only the speaker that was missing.

Case 3: Two speeches stored as one statement

Case 1 involved errors in our processing that caused a single speech to be stored as two statements. Case 3 is the opposite problem of storing multiple speeches as a single statement. Both Congressional Record formatting quirks and errors in our processing contribute.

Case 3a: Titles printed in lowercase in the Congressional Record

Title detection is already difficult because the Record uses a mix of ALL CAPS and standard Title Case for headings. GPO usually prints the first heading in ALL CAPS and later headings in Title Case. The different casings are not a hierarchy. A Title Case heading is not a subtitle or subheading of the ALL CAPS heading above it. Instead, each one marks a separate item at the same level.

During our investigation we also found a third heading casing, entirely lowercase. These look like obvious GPO formatting errors—headings that should be Title Case or ALL CAPS printed in lowercase instead. Our detector had no rule for that casing. As a result, we did not recognize them as titles. In our 2024–2026 load we found roughly forty such cases.

One example was Representative Earl L. “Buddy” Carter’s Extensions of Remarks on May 14, 2026. Carter gave twenty-one separate tributes, collected into a single file in the Congressional Record (CREC-2026-05-14-pt1-PgH3524.htm). Each tribute had its own title—twenty-one titles in all: one in ALL CAPS, sixteen in Title Case, and four in lowercase. We caught the ALL-CAPS and Title-Case headings; the four lowercase titles went undetected. Selected tributes as they appeared in the Record are reprinted in part below.

As published in the Congressional Record Titles bolded for clarity; they are not bolded in the source file.
                        RECOGNIZING GRIFF LYNCH

  Mr. CARTER of Georgia. Madam Speaker, I rise today to recognize Griff
Lynch for his outstanding service as president and CEO of the Georgia
Ports Authority.
# … tribute continues …


                 Honoring Life and Legacy of Ted Turner

  Mr. CARTER of Georgia. Madam Speaker, I rise today to honor the life
and the legacy of Ted Turner, the founder of CNN and a former Savannah
resident.
# … tribute continues …


                Honoring the Legacy of William Ligon III

  Mr. CARTER of Georgia. Madam Speaker, I rise today to honor the
memory and the legacy of William Ligon III. Will tragically passed on
May 3 after a life full of compassion and service to others.
# … tribute continues …


              recognizing the savannah country day school

  Mr. CARTER of Georgia. Madam Speaker, I rise today to recognize the
Savannah Country Day School faculty, staff, and parents' association.
# … tribute continues …


                   recognizing the port of brunswick

  Mr. CARTER of Georgia. Madam Speaker, I rise today to recognize the
Port of Brunswick for their second year in a row as the busiest
automotive port in the country.
# … tribute continues …

When our parsing logic encountered a lowercase heading, it was not detected as a title—the line was treated as ordinary statement text instead.

Our processing uses speaker bylines to trigger new statements—the standard way the Congressional Record marks who has the floor. When a missed lowercase heading sat immediately before a byline, two problems followed:

1. Because the lowercase line was not recognized as a heading, it was treated as statement text and stored as the last line of the previous statement—as if the member spoke it.

2. The byline then triggered a new statement, but with no new title detected, our title carryover logic assigned the last detected title.

The fix

The fix is case agnostic and is discussed below in Case 3c, where a single detection method addresses Cases 3a, 3b, and 3c together.

Case 3b: Title Case headings with numbers in the Congressional Record

The second failure mode we found was that our Title Case parsing logic did not recognize titles when a word in the title contained a number. Our Title Case check determined whether a line was a title by testing each word individually. When a word failed the test, the title was not detected, and the line was stored as ordinary statement text instead.

One example was Representative Michael Baumgartner’s Extensions-of-Remarks on September 9, 2025, where he gave two tributes. One tribute was titled after the organization Active4Youth. Our Title Case check did not recognize this title due to the digit in the organization’s name.

As published in the Congressional Record Titles bolded for clarity; they are not bolded in the source file.
                         Honoring Roger Reed

  Mr. BAUMGARTNER. Mr. Speaker, I rise today to honor the life of Roger
Reed, a man whose legacy is defined not only by his distinguished legal
career but also by his deep commitment to his community.
# … tribute continues …
  Roger Reed was a great man, a great friend, and we honor his legacy.


                        Commending Active4Youth

  Mr. BAUMGARTNER. Mr. Speaker, as the father of five, with my youngest
daughter attending her very first cross-country practice today, I rise to
commend Active4Youth…
# … tribute continues …
Title not detected

The Title Case checking logic was meant to discriminate titles from body text. It was not a deliberate rule against numbers—we had simply not accounted for common Record patterns such as anniversary ordinals or organization names written with a digit.

A second example was Representative Ben Cline’s Extensions-of-Remarks on September 24, 2024, where he also gave two tributes. We detected the first heading, for the Bank of Botetourt’s 125th anniversary, but not the second, for Muhlenberg Lutheran Church’s 175th anniversary. The difference was the detector each heading went through. The opening heading appears in the Congressional Record in all caps and was detected by our ALL CAPS logic. The second heading appears mid-page in Title Case. The check stripped non-letters from each word before testing it; on 175th that left th, which failed the check, so the heading was not recognized.

As published in the Congressional Record Titles bolded for clarity; they are not bolded in the source file.
        RECOGNIZING BANK OF BOTETOURT'S 125TH ANNIVERSARY

  Mr. CLINE of Virginia. Mr. Speaker, I rise today to honor a cornerstone
of our community, the Bank of Botetourt, as they celebrate 125 years of
service to the people of Botetourt County.
# … tribute continues …


     Recognizing Muhlenberg Lutheran Church's 175th Anniversary

  Mr. CLINE of Virginia. Mr. Speaker, I rise to recognize an incredible
milestone for Muhlenberg Lutheran Church in Virginia's Sixth District as
they mark 175 faithful years…
# … tribute continues …

When a missed Title Case heading sat immediately before a byline, the same two problems from Case 3a followed: the heading line was stored as the last line of the previous statement, and the byline triggered a new row under the last detected title.

The fix

The fix is case agnostic and is discussed below in Case 3c, where a single detection method addresses Cases 3a, 3b, and 3c together. Because that method does not rely on the Title Case word check, it also covers anniversary ordinals such as 175th and organization names with an embedded digit such as Active4Youth.

Case 3c: Titles with no speaker byline after them in the Congressional Record

The third failure mode we found was titles with no speaker byline after them in the Congressional Record. When a member keeps the floor and moves to a new subject under a new title, GPO sometimes prints that title without reprinting the member’s byline. Our detector requires a speaker byline (for example, Mr. SCHUMER.) to immediately follow a title. When GPO omits it, our detector does not recognize the line as a title.

When a title goes undetected because no byline follows, two things happen:

1. The title is not detected. It is treated as statement text—as if the member spoke it.

2. The member’s remarks continue in the same statement under the first title.

One example is Senator Chuck Schumer’s remarks in the Senate on March 11, 2026 (CREC-2026-03-11-pt1-PgS969-8.htm). The first title, Iran, was detected because Mr. SCHUMER. followed it. The next two titles were not:

As published in the Congressional Record Titles bolded for clarity; they are not bolded in the source file.
                                  Iran

  Mr. SCHUMER. Well, while Americans are still in the dark for why we
are at war, each passing day gives us a cleaner picture of the cost of
war.
# … Iran remarks continue …
  Americans don't want war--not Republican voters, not Independent
voters, not even many of Donald Trump's MAGA base. They feel betrayed
by what has happened in the Middle East, and they feel betrayed by the
Senators in this Chamber who refuse to stand up for the Constitution
and refuse to put a check on Donald Trump's belligerence--belligerence
that doesn't seem to have much of a rhyme or reason from day to day.


                    Department of Homeland Security

  On DHS, Republicans, for weeks, have refused to address some of the
most egregious abuses from ICE that we have seen and that have plagued
cities like Minneapolis and so many other cities around the country.
Democrats have offered multiple rounds of proposals, and we are
serious--very serious--about getting something done. But Republicans
need to show that they are serious also, and we have a lot of work left
to do.
# … DHS remarks continue …


                            SAVE America Act

  On the SAVE Act, Donald Trump has given Republicans in Congress a
ridiculous ultimatum: Help him thoroughly undermine our democracy or he
will bring all legislation to a screeching halt. What kind of President
is this? It sounds like a pouting second grader.
# … SAVE Act remarks continue …

At parse time, Schumer’s Iran, Department of Homeland Security, and SAVE America Act remarks were one 1,426-word statement under the title Iran.

A complication: headings inside inserted documents

Recovering Schumer’s missed titles is not the whole problem. A member can include a document in the Record—court summaries, a letter, an agency report—and GPO prints headings inside that document the same way it prints titles in floor speech: centered, with blank lines above and below. Those lines have the same shape as a real title, but they are not new topics.

On February 3, 2026, Representative Jimmy Patronis entered a single Extensions of Remarks statement titled True Cost of Big Tech (CREC-2026-02-03-pt1-PgE94.htm). Inside the statement he included summaries of several court cases, and each summary has its own centered line:

As published in the Congressional Record Headings bolded for clarity; they are not bolded in the source file.
                         TRUE COST OF BIG TECH

                          HON. JIMMY PATRONIS

  Mr. PATRONIS. Mr. Speaker, Section 230 of the Communications Decency
Act insulates ``Big Tech'' from most liability for the digital fentanyl
promoted on their sites.
# … statement continues …
  While I could fill hundreds of pages with stories about how social media is
harming our youth and supplement it daily, I want to focus on stories from my
district and my home state of Florida.
  As a successful Section 230 defense often results in the court granting
dismissal early in the litigation, the facts are often accepted as plead. In
these instances, the excerpts below reflect the claims as plead by the victims
and their families.

   Craigslist Faces No Accountability for Allegedly Facilitating Sex
                      Trafficking of a 15-Year-Old

       Back in 2008, a then fifteen-year-old girl began to allegedly
     be forcibly trafficked for commercial sex...

                     Emerging Threat of AI Chatbots

       Beyond platforms serving as a predator superhighway,
     today's parents must contend with AI chatbots...
# … more case summaries, each with its own centered heading …

The fix

The fix had to solve both problems: recover titles like Schumer’s, without recording Patronis’s case-summary headings as new topics. We stopped treating the speaker byline as the only signal that a line is a title, and instead decide in three steps.

This detection method is case agnostic—it never depends on the casing of a heading—so the same fix also addresses Cases 3a and 3b above. It recovers the lowercase headings from Case 3a and the headings with embedded numbers from Case 3b, in addition to the missing-byline headings that are the subject of this section.

Step 1: Find a line that might be a title. We look for a centered line with a blank line above and below the line, and no sentence-ending punctuation. We also exclude lines with certain markers we know are not titles, but might otherwise fit this pattern: page numbers, bracketed citations, and the metadata GPO prints at the top of an Extensions of Remarks entry.

Step 2: Read the following line. The following line is the line GPO prints right after a line that might be a title. We sort the following line into one of four kinds: a speaker byline (Mr. CARTER.), an address to the chair (Mr. President, …), ordinary floor prose, or text from a document inserted into the Record.

  1. A speaker byline (Mr. CARTER.). GPO normally reprints the member’s name when they begin a new topic, so this is the strongest signal that a potential title is real. When the conditions in Step 1 and Step 2 (a) are both met, we record the potential title. We do not pass the potential title to Step 3 for further processing.
  2. An address to the chair (Mr. President, …). When the next line after a potential title is an address to the chair, this indicates the same member has kept the floor without a fresh byline. This often indicates the speaking member has moved on to a new subject. Therefore, the potential title line may be a real title. However, inserted documents can also follow this pattern (see above), so we pass the potential title to Step 3 for further processing.
  3. Ordinary floor prose (On DHS, Republicans …). When the next line after a potential title is ordinary floor prose, this indicates the same member has kept the floor without a fresh byline and without an address to the chair. The speaking member may have moved on to a new subject. Therefore, the potential title line may be a real title. This is the case, for example, in Schumer’s statements from Case 3c above. However, ordinary floor prose is the weakest of the four Step 2 signals and is also a strong possible indication that the potential title is not a real title, so we pass the potential title to Step 3 for further processing.
  4. Text from a document inserted into the Record (Back in 2008, …; see above). When the next line after a potential title is text from a document the member inserted into the Record, the potential title is a heading inside that document. We detect this using indentation, since documents inserted into the Record are indented more than standard floor speech. In this case we can rule out the potential title as being a real title and skip Step 3.

Step 3: Rule out headings inside inserted documents. This step applies only to (b) and (c). Step 2 can leave a potential title unsettled: a heading inside an inserted document can have an address to the chair or ordinary floor prose on the next line, just as a real title can. Step 3 checks the lines around the potential title:

  1. The line above the potential title. The line immediately above the potential title must be indented like ordinary floor speech, not like text from a document inserted into the Record (see Step 2 (d)). If the line above the potential title is already at the deeper indentation GPO uses for included material, the potential title is a heading inside that material, not a new topic in the member’s speech.
  2. The potential title. The potential title must still meet the Step 1 criteria: centered, with no sentence-ending punctuation. When Step 2 (c) classified the next line as ordinary floor prose, we also require proper title casing on the potential title.
  3. The line that continues the opening paragraph. This check applies only when Step 2 (c) classified the next line as ordinary floor prose. The next line after the potential title opens a paragraph of the member’s speech. The line after that—the one that continues the same paragraph—must also be indented like ordinary floor speech, not like text from a document inserted into the Record. Some headings inside included material are followed by one line at normal indentation and then more deeply indented text; this check catches that pattern.

When all applicable checks pass, we record the potential title. When any check fails, we do not record the potential title.

We apply these steps to every candidate line in an entry, including the first heading. Previously, our detector treated the top heading separately, since it usually appears in ALL CAPS. That separate rule could lock onto an ALL CAPS line lower on the page—such as a vote tally like YEAS--60—and skip the real heading above it. Our new logic unifies heading processing across all titles in a file, better handling titles throughout the file.

Why we did not use GPO's metadata for titles

There is a shortcut we considered here and decided against. Along with the HTML and PDF of each day’s Record, GPO publishes a MODS file. MODS is an XML metadata format—Metadata Object Description Schema, a standard from the Library of Congress. For each HTML file in that day’s Record, MODS lists a title, the speaking member, the date, and page numbers. One row from the file looks like this:

From the MODS file for March 18, 2026
<relatedItem type="constituent" ID="id-CREC-2026-03-18-pt1-PgE229-2">
  <titleInfo>
    <title>HONORING YOHAN BLAKE</title>
  </titleInfo>
  ...
</relatedItem>

The obvious idea is to skip detecting titles ourselves and read them from MODS instead. We tested that and decided against it for two reasons.

1. MODS provides just one title per file, even if the file itself contains more. Consider the example ofRepresentative Carter’s remarks on May 14, 2026 (CREC-2026-05-14-pt1-PgH3524.htm). This file contains 21 separate tributes, yet MODS names only the first one and says nothing about the other 20. Across the days we checked, 292 files held more than one topic like this. Reading titles from MODS would collapse each of those files into a single title.

2. Because MODS titles are formattedin ALL CAPS they don’t help solve the capitalization problem in Case 4 either.

Case 3d: Different titles grouped as one topic

The fourth failure mode we found was different titles grouped as one topic. In our model, a topic is a title, so two different titles should mean two different topics. Unlike Cases 3a–3c, this one is downstream of our initial parsing logic.

This matters because of how we present statements to readers. In our UI we group statements by topic, so a reader can see everything said about a subject in one place and in order—the floor’s back-and-forth read as a single conversation. A title is just the label on one statement; a topic is the thread that gathers every statement sharing that title. Without it, one debate would be scattered across dozens of separate statements from different members, spread over the day and across separate published files. The topic stitches them back into a single conversation a reader can follow start to finish. When statements with different titles fall into the same topic, that conversation quietly mixes subjects, and a reader following one topic ends up reading remarks that belong to another.

The cause was a mismatch between two steps that ran in sequence. During initial parsing, a member’s continuous run of remarks was given a single title. Our LLM cleaning step ran next. This step was meant as a guard to further refine any gaps our programmatic logic might have missed, such as lingering administrative content or missed titles. It was this second case that caused the problem, and it was exactly Case 3c: when parsing missed a title, that title was not lost—it stayed buried in the statement text, alongside the member’s remarks. The cleaning step read that text, found the title sitting inside it, and pulled it out, splitting the one statement into the correct statement-and-title pairs.

That fix was correct for the statements, but the topic did not get updated. Cleaning gave each statement the right title, but they still shared the same topic parsing assigned. We group by topic, not by title, so the segments stayed together even though their titles differed.

Senator Chuck Grassley’s remarks in the Senate on April 15, 2026 (CREC-2026-04-15-pt1-PgS1749-2.htm) were one example. The Congressional Record file as published contained two headings: Iowa, then FISA Section 702 Reauthorization. Parsing incorrectly stored both under the title of Iowa because it missed the FISA heading, leaving that heading in the Iowa statement text. LLM cleaning then correctly split them into two statements and titled the second FISA Section 702 Reauthorization, but both statements were still stored under the same Iowa topic. Below is how that looks to a reader on Second Congress. The page shows two rows with two different titles. The “Show all 2 statements about this topic →” selector is an error: click it and both statements are grouped together, because they still share the Iowa topic. That one topic should have become two topics, one per title. Once it is split, Iowa has one statement and that selector is gone.

The Iowa topic, as shown on Second Congress
Chuck Grassley
Chuck Grassley Republican Iowa Senate
Iowa
Statement 1 of 2 on this topic.
Show all 2 statements about this topic →
This was a spoken statement made in the Senate on 15 April 2026. The statement contained 473 words and appeared on pages S1751, S1752.
View Congressional Record PDF →

I have two items I would like to discuss. During the Easter break when the Senate was not in session, I was holding in Iowa Q&A’s in 25 of our 99 counties. My annual practice allows me to hear directly from the grassroots.

… Iowa remarks continue

Chuck Grassley
Chuck Grassley Republican Iowa Senate
FISA Section 702 Reauthorization
Statement 2 of 2 on this topic.
Show all 2 statements about this topic →
This was a spoken statement made in the Senate on 15 April 2026. The statement contained 952 words and appeared on pages S1751, S1752.
View Congressional Record PDF →

Now, on another subject—and more critical because of timing—deals with FISA Section 702 reauthorization. In 5 short days, Section 702 of the Foreign Intelligence Surveillance Act—FISA for short—is set to expire.

… FISA remarks continue

Title does not match the topic

The fix

When LLM cleaning splits a topic’s statements and assigns a segment a title different from the topic’s title, we now create a new topic object with that title and move the segment into it. Segments before the first new title stay in the original topic. Everything after a new title attaches to that topic until cleaning finds the next one—the same rule parsing uses within a file.

At load time, if a statement still has a title that differs from its topic’s title, we skip that row and log an error so the case can be reviewed manually. The rest of the day’s load continues.

Case 4: A correct title stored with wrong capitalization

The Congressional Record does not print headings in one consistent style. The same kind of heading can appear in ALL CAPS, in Title Case, or in lowercase, sometimes within a single file. Case 3a showed exactly this: Representative Carter’s twenty-one tributes carried headings such as RECOGNIZING GRIFF LYNCH (ALL CAPS), Honoring Life and Legacy of Ted Turner (Title Case), and recognizing the port of brunswick (lowercase) on the same day. If we had stored each heading exactly as printed, our site would have shown that same inconsistency—some titles shouting in capitals, others whispering in lowercase, with no rhyme or reason.

In our original flow, once a title was detected we standardized it to Title Case, the normal convention for headings, so every title was presented the same way regardless of how the Record happened to print it. The rule was blunt: it capitalized the first letter of each word and lowercased every other letter. For ordinary words that was correct. But some words are written with capital letters beyond the first, and lowercasing those letters changed the word into something wrong.

We found several kinds of words this happened to. Acronyms are written in all capitals, so lowercasing everything after the first letter turned WRDA into Wrda, NDAA into Ndaa, and FISA into Fisa. Proper names sometimes carry capitals inside them: Representative Doug LaMalfa became Lamalfa, Congresswoman Cathy McMorris Rodgers became Mcmorris, and Patrick O’Brien became O’brien. Roman numerals are all capitals, so Title IX became Title Ix and Pope Leo XIV became Pope Leo Xiv. Company and brand names that capitalize letters inside the name had the same problem. These were the kinds of titles we found so far; there may be others.

For acronyms we kept a hand-maintained list (FBI, NATO, GDP, and so on) that we forced back to all capitals after standardizing, and we special-cased the common name suffixes (II, III, IV). But the list only covered acronyms we already knew about, and we could not anticipate every one, and there was no equivalent safety net for names or for the higher Roman numerals at all. Anything we did not anticipate stayed mangled. Across the roughly 50,000 statements we loaded, at least 200 had titles stored with the wrong capitalization this way.

Senator Mitch McConnell’s December 18, 2024 floor remarks introducing the Water Resources bill were one example. They were filed in the Record under the heading WRDA, the acronym for the Water Resources Development Act. We detected the title correctly, but WRDA was not on our acronym list, so standardizing it to Title Case rewrote it as Wrda.

As published in the Congressional Record Title bolded for clarity; it is not bolded in the source file.
                                  WRDA

  Mr. McCONNELL. Mr. President, last week, the House passed the Water
Resources bill with broad bipartisan support. Today, it is the Senate's
turn to act.
# … statement continues …

The title was stored and displayed as a lowercased acronym:

As stored
Wrda

Mr. President, last week, the House passed the Water Resources bill with broad bipartisan support. Today, it is the Senate’s turn to act…

Title stored in the wrong case

The fix

We added a dedicated pipeline step that recases titles with GPT-5.4-mini after parsing and title assignment. The model receives the title as printed in the Record and returns the same words with correct capitalization. These steps of the process are:

  1. Send the title with context from the statement. Along with each title, we pass the opening of the first statement filed under it. Casing is often ambiguous without it: SAVE is an acronym in “the SAVE Act” but an ordinary word in “Save Our Seas.” The body of the speech is where the context for the title is provided.
  2. Accept only casing changes. The model’s answer is checked character by character. Every letter, space, and punctuation mark must match the original except for case. If the model reworded the title the result is rejected and resubmitted; if it fails repeated attempts we fall back to the old deterministic recaser.
  3. Send only titles that need recasing. We skip administrative headings and titles already written by a model earlier in the pipeline (Congress.gov bill names, titles generated by the LLM during cleaning or title assignment). Many statements share a title, so we deduplicate to one request per distinct title per day and apply the result everywhere that title appears.

McConnell’s WRDA remarks are now stored under WRDA, not Wrda.

Case 5: Stored statements missing text present in the published Record

The fifth problem we found involved errantly removing opening and closing text from statements during processing. The cause was poor prompting in our LLM cleaning step. In our effort to clean statements of any administrative content, we had overcorrected how we instructed GPT-5.2.

In some cases openings were trimmed so a statement began mid-sentence. In other cases closings were trimmed so a statement ended before the member finished. We grouped the trim failures into Case 5a and Case 5b because they share the same cause.

Case 5a: Stored statements missing the opening text present in the published Record

The first example we noticed was Senator Mike Crapo. In a statement on February 10, 2026, what we stored in our database began with “the resolution seeks to overturn a Trump administration IRS notice…” In the published Record, a long procedural clause came before that sentence. Below is the opening as GPO published it, showing the text we dropped and where our stored version incorrectly started.

As published — opening
Corporate Alternative Minimum Tax to Partnerships

Madam President, reserving the right to object to what I expect to be a unanimous consent request with regard to S.J. Res. 95, the resolution seeks to overturn a Trump administration IRS notice providing simplified guidance on applying the corporate alternative minimum tax to partnerships. The corporate alternative minimum tax is a fundamentally flawed, Democrat-enacted book minimum tax. Not one single Republican voted for it.

As Republicans predicted, the book minimum tax has proven to be highly complex and burdensome. Even President Biden’s own Treasury Department acknowledged its dizzying complexity. They waived penalties related to it for 2 full years due to the “continued challenges” of compliance.

Real opening that should have been stored
Where our stored version begins

The missing opening was caused by how our pipeline cleans administrative content. Statements that are purely procedural—for example, a quorum call, a motion to adjourn, or a unanimous-consent request with no policy remarks—are handled programmatically during parsing and never loaded as member statements. However, it is impossible to anticipate every case of administrative content, so we cannot programmatically remove all of it.

Instead, we use a backstop. After programmatic parsing, a smaller LLM (GPT-5.4-mini) reads each statement and sets a flag if it finds quorum calls, yields, unanimous-consent language, objections, or other procedural content mixed in with the member’s remarks. That step does not edit the text—it only decides whether the statement needs cleaning. If the small LLM sets the flag to true, the full statement is passed to a larger LLM (GPT-5.2), which either excludes it entirely if the statement is all administrative, or returns a version with the procedural parts removed.

Most floor statements include some procedural language—“Mr. Speaker,” a yield, a reservation of objection—mixed in with the member’s remarks, and that is fine. The cleaning step is only supposed to peel off procedural wrapper when it is separable from the substance. For Crapo, GPT-5.4-mini set the flag, and GPT-5.2 tried to remove the objection framing: “Madam President, reserving the right to object to what I expect to be a unanimous consent request with regard to S.J. Res. 95,” But that clause is grammatically fused into the same sentences as his policy argument. The cleaning model treated that fused language as removable procedural content and trimmed past it, leaving the stored statement to begin mid-sentence.

The cleaning prompt instructed the large LLM to remove procedural openings. This led to acceptable outcomes in almost all cases. Only occasionally would the model trim an opening it should have kept, and even then the damage was typically minimal. For example, in a statement that started, “Thank you, Mr. Speaker. Mr. Speaker, I am here today to discuss…” it might remove the first sentence, “Thank you, Mr. Speaker.” The Crapo statement exposed a more serious failure: the large LLM should never have cut a statement so that it began in the middle of a sentence. We subsequently discovered more than two dozen similar examples.

In fact, by the time we found the Crapo example we had already rewritten the LLM cleaning prompt. We did this to improve our media-cutting workflow. While creating fine-tuning data we noticed that our stored written statements often had an opening or closing sentence missing. In most cases, as described in the previous paragraph, the trim was minor: the model might remove a standalone greeting like “Thank you, Mr. Speaker” from an opening that continued “Mr. Speaker, I am here today to discuss…” That kind of loss has no impact on meaning, but it does make matching transcribed statements to their written version more difficult, since the LLMs used in our media processing have to learn a more complex policy—allowing for more variation and ambiguity in when a statement starts and ends.

Matching statements and transcripts is already a challenging task, which is part of why we rewrote the cleaning prompt. The new instructions fixed the problem for statements cleaned after the change. However, they obviously do not restore text already trimmed from statements we loaded under the old prompt. That missing text is not easily recoverable without reprocessing, but that reprocessing is preferable if our media-processing stage is to be optimized. More complete statements with accurate opening and closing text are a primary reason we have decided to reprocess the 2024–2026 statements.

Case 5b: Stored statements missing the closing text present in the published Record

We found that the LLM cleaning prompt also trimmed closing passages we wanted to keep. The Crapo statement discussed above in the context of trimming openings also had this closing trimming issue.

As published — closing
Corporate Alternative Minimum Tax to Partnerships

Approving this resolution would revive ambiguity, inviting audits, litigation, and significant compliance costs. Therefore, I register my objection when the unanimous consent request is made.

Real closing that should have been stored
What we stored in our database — closing
Corporate Alternative Minimum Tax to Partnerships

Approving this resolution would revive ambiguity, inviting audits, litigation, and significant compliance costs.

Closing trims are harder to detect than opening trims. When an opening is missing, the absence of the address to the chair—“Mr. Speaker” or “Mr. President”—is often a clue that something was cut off. GPO generally publishes speeches with that address even when the oral statement did not begin with it, so an opening that jumps straight into the substance stands out. Closings are less uniform. Members yield back time in many different phrasings, and there is no equivalent tell that a closing was trimmed.

To analyze trimmed closing statements, we sampled both the raw Congressional Record files and our cleaned output for 15 days—about 1,400 Congressional Record files in total. We re-parsed each raw file and diffed it against the cleaned version we had stored, counting closing statements that had been trimmed by our processing. We found 21 cases of trimmed closing statements.

The fix for Cases 5a–5b

Extrapolating that error rate across all statements already processed for 2024 through 2026 showed that patching statements manually would be time-consuming. Given we had already corrected the LLM cleaning prompt known to have caused both opening and closing trimming—together with the other issues discussed in this post—we decided to reprocess 2024–2026.

Case 6: The wrong bill linked to a statement

Crapo’s statement turned up a second, unrelated problem. When a statement names a bill, we link a record in our legislation database to the statement so a reader can click through to the actual bill text and status.

While repairing Crapo’s trimmed text, we noticed we had linked the wrong bill to his statement. Crapo had been speaking about a Senate joint resolution (S.J. Res.)—a type of resolution Congress uses to disapprove a federal rule or agency action—and we had linked the wrong piece of legislation to it. The specific S.J. Res. in this case was number 95: the 118th-Congress version, when he was objecting to the 119th-Congress version. That sent us digging into both pipeline steps. We grouped the failures into Case 6a, Case 6b, Case 6c, and Case 6d.

Case 6a: Bill numbers matched without the Congress in session

Bill numbers—and sometimes titles—repeat every Congress. Crapo was speaking about S.J. Res. 95 in the 119th Congress, a disapproval of the Treasury/IRS corporate-AMT-to-partnerships notice. We had linked a different S.J. Res. 95 to his statement—the 118th-Congress EPA coal-ash disapproval.

What we linked
S.J. Res. 95 — 118th Congress

A joint resolution disapproving the EPA rule on the “Disposal of Coal Combustion Residuals.” Unrelated to anything Crapo said.

What it should have been
S.J. Res. 95 — 119th Congress

A joint resolution disapproving the Treasury/IRS notice on applying the corporate alternative minimum tax to partnerships—the exact resolution Crapo rose to object to.

When we processed Crapo’s statement, the parser had picked up S.J. Res. 95 as a numbered bill in his remarks. Our legislation processing then matched it to a row in our database using the bill number alone. Nothing in that step used additional context to resolve a bill number that can appear in more than one Congress.

Crapo was objecting to the 119th-Congress resolution; we had linked the 118th-Congress bill to his statement. That exposed two more problems, which we take up next.

Case 6b: Descriptive bill titles matched with fuzzy string similarity

While Case 6a was about bill numbers, we also discovered problems with our processing of bill titles. Rather than citing a bill number, members often name legislation by its title. During the July 10, 2024 House debate on H.R. 8281, for example, Representative Bryan Steil rose “in support of the Safeguard American Voter Eligibility Act, known as the SAVE Act”—naming the bill by title, not number.

Bill title detection started during LLM annotation, a part of the pipeline we run for several types of detection, including administrative content, artifacts inserted in the Record, multiple speakers, and legislation. During annotation, a small LLM read each statement and set a flag when the speaker named legislation by a descriptive title.

Statements with the flag were sent to a second LLM pass whose only job was extraction: return the exact title string as spoken—“Safeguard American Voter Eligibility Act,” “SAVE Act,” and so on.

The matcher scored rows in our legislation database against the extracted title with a weighted blend of token overlap (60%) and character-sequence similarity (40%). The highest-scoring candidate above a fixed threshold of 0.55 was attached automatically without any further matching. The matching code was LLM-generated, and we did not review it carefully enough. The output passed spot checks, but digging in more detail it was clearly wrong. The legislation attached to each statement was often incorrect, which caused confusion when reviewing statements in the frontend UI.

Case 6c: Bills and amendments missing from our legislation database

Cases 6a and 6b also rested on an incomplete legislation database. We match against our own ingested copy of congressional legislation. For our initial testing, we ingested legislation only for the Congresses whose statements we were also processing. However, members sometimes cite bills from earlier sessions. When legislation from those earlier Congresses was not in our database, matching could only land on whatever was present, often a same-numbered bill from a Congress we happened to have loaded.

The fix for Cases 6a–6c

We rebuilt how we detect and link legislation references end to end—one detection pass, one resolver—including amendments, which the old pipeline neither ingested nor detected. The pipeline now has two distinct stages, and the two jobs never mix: detection finds what was said; resolution decides which bill in which Congress.

Stage 1: Detection

We find which piece of legislation the speaker named—a bill number, an amendment citation, or a descriptive title—without deciding which bill or Congress they meant. Nothing is matched or linked in this stage.

  1. Bill numbers and amendments. During parsing, regex scans each statement and its title for citations like “H.R. 4465” or “H.Amdt. 225.” We store the citation as it appears in the Record, including a trailing year when the speaker gives one (“H.R. 4465 of 2023”).
  2. Descriptive titles. We scan statement text with a regex for capitalized phrases ending in words such as “Act,” “Law,” or “Resolution.” When that regex matches a phrase, the statement skips the next step, LLM annotation. When that regex does not match a phrase, we send the statement to GPT-5.4-mini as a backstop. GPT-5.4-mini does not extract titles; it only sets a flag if the speaker named legislation in a form the regex cannot see, such as “Obamacare.”

Stage 2: Resolution

Every detected piece of legislation runs through a unified matching process; this includes bill numbers, short and long bill names, and amendments. We normalize each piece of legislation into a canonical format: “H.R. 4465” becomes “House Bill 4465,” “S. 223” becomes “Senate Bill 223.” We then match the normalized format against our complete ingested copy of congressional legislation, attempting to resolve it to a specific Congress. The full processing flow is outlined below.

  1. If the speaker’s reference includes a year (“H.R. 4465 of 2023”), we limit the search to the Congress that year covers.
  2. If no year is given, we assume the reference belongs to the Congress the speaker is sitting in.
  3. If that Congress has no match, we widen the search to earlier Congresses—speakers do sometimes reach back to earlier sessions.
  4. If the search turns up a single bill, we assume this is the one being referenced and attach it to the statement.
  5. If it turns up more than one, we hand the candidates and the surrounding statement context to an LLM to disambiguate.
  6. If even that is not conclusive, we list all the possible bills the reference might have meant, with the years each spans. This appears in the statement’s detail view in our Browse UI on Second Congress.

Case 6d: House Rules Committee amendment numbers that do not match Congress.gov

Detecting amendments mentioned within statement text turned out to be challenging in some cases. There are two different kinds of amendment mentions.

  1. In the Senate. The amendment number a speaker refers to—“Amendment No. 2360,” say—is the number Congress.gov files it under (S.Amdt. 2360). This case is easy to handle, as each mention resolves directly to its official amendment number.
  2. The House is more complex. There, amendment mentions refer to a local sequence number assigned by the Rules Committee, and it does not match the H.Amdt. number Congress.gov later assigns. What makes things even more complex is that many House amendments are voted down in the Rules Committee, so they never receive an H.Amdt. number at all—though members may still refer to them on the floor. Consider Representative McGovern, who noted on the House floor that the Rules Committee had blocked “amendment No. 2 to H.R. 7176 … offered by Representative Houlahan” from reaching the floor for a vote.

    Resolving these House mentions would mean scraping each bill’s Rules Committee amendment table to translate the local number into a sponsor and purpose, then matching that against the amendments Congress.gov actually numbered—while accepting that many mentions still resolve to nothing, because amendments killed in committee never become records in the first place. That requires a separate data pipeline, so for now we have deliberately left this for a future addition.

The fix

Senate amendment mentions resolve directly to the number Congress.gov files them under, so we handle those today. House Rules Committee numbers need a separate pipeline to translate each local number against Congress.gov, which we have deliberately left for a future addition.

Case 7: GPO editorial notes left in statement text

The Congressional Record is published quickly so that followers of Congress have access to up-to-date information. For that reason mistakes occasionally make it into print—misattributed speakers, incorrect page references, or typos in spoken statements. When GPO catches an error it leaves it in place rather than reprinting a corrected version. Instead it appends an editorial note recording what was printed and what the corrected online version should read. These notes are GPO metadata about the document, not anything a member said on the floor. They are rare—we found roughly 180 affected statements out of the nearly 50,000 in our first round of ingestion, well under one half of one percent.

GPO inserts these corrections inline, delimited by ===== NOTE ===== and ===== END NOTE =====. We were unaware of this GPO note pattern when we created our cleaning pipeline and so did not filter them out. This caused the notes to be stored as part of statement text, which caused END NOTE lines to be detected as titles.

Case 7a: Editorial note stored as part of statement text

The first problem was storing the GPO note as statement text. In eleven loaded statements, the full NOTE block was stored verbatim as if the member had spoken it.

One example was Representative Bennie G. Thompson’s tribute to Brigadier General Donna R. Williams in the House Extensions of Remarks on October 21, 2025. A GPO correction sits mid-sentence. The published source and what we stored appear below.

As published in the Congressional Record
  Mr. THOMPSON of Mississippi. Mr. Speaker, I rise today

=========================== NOTE ===========================
On October 21, 2025, page E980, in the second column, the
following appeared: Mr. THOMPSON. Mr. Speaker, I rise today

The online version has been corrected to read: Mr. THOMPSON of
Mississippi. Mr. Speaker, I rise today
========================= END NOTE =========================

to recognize Brigadier General Donna R. Williams, Retired, who has been
named the 2025 Honorary Chairperson of the local chapter of the
National Alliance on Mental Illness. Brigadier General Williams was
selected for this honor in recognition of her longstanding community
involvement and her distinguished service to our Nation. She served
honorably for over 31 years in the United States Army, culminating her
career as the Deputy Commanding General (Support) of the 412th Theater
Engineer Command, located in Vicksburg, Mississippi.
# … tribute continues …
What we stored in our database
Honoring Brigadier General Donna R. Williams, Retired

Mr. Speaker, I rise today
=========================== NOTE ===========================
On October 21, 2025, page E980, in the second column, the following appeared: Mr. THOMPSON. Mr. Speaker, I rise today

The online version has been corrected to read: Mr. THOMPSON of Mississippi. Mr. Speaker, I rise today
========================= END NOTE =========================

to recognize Brigadier General Donna R. Williams, Retired, who has been named the 2025 Honorary Chairperson of the local chapter of the National Alliance on Mental Illness. Brigadier General Williams was selected for this honor in recognition of her longstanding community involvement and her distinguished service to our Nation. She served honorably for over 31 years in the United States Army, culminating her career as the Deputy Commanding General (Support) of the 412th Theater Engineer Command, located in Vicksburg, Mississippi.

GPO editorial note stored as statement text

Case 7b: One speech stored as two statements when the END NOTE line is detected as a title

The same root cause could also split one speech into two statements. Our title detector marks a new title only when a title line is immediately followed by a member byline, though during this analysis we discovered that the byline check after a title is looser than we intended. A line that begins with Mr., Ms., or Mrs. can trigger the title detection logic even when it is not part of a byline (see example below). This looseness was an oversight. Since NOTE and END NOTE delimiters meet the general criteria for a title—after stripping special characters both are all caps and have blank lines before and after, respectively—an honorific following a note caused the note to be picked up as a title.

As Case 3 describes, there were already issues with title detection that required improving the parsing logic. What’s more, removing notes was a simple pre-processing step (see fix below). For this reason no additional changes to title detection were needed in light of GPO’s note markers.

One example of a note block splitting a speech into two statements was Representative J. French Hill’s tribute to Curtis Ferguson in the House on September 18, 2024. Hill opened with one sentence, then GPO inserted a correction note before the rest of his remarks. The END NOTE delimiter met our title criteria. The next line was “Mr. Ferguson’s big personality and civic leadership…” That is not a speaker marker; it is Hill still talking about Ferguson. Our previous speaker-marker regex was too weak: it treated any line that begins with Mr. followed by a capitalized word as a byline, so END NOTE was stored as a title and the tribute was split into two statements. The first statement kept the title Recognizing Curtis Ferguson but ended on a dangling NOTE opener. The second statement took the END NOTE line as its title and held the rest of the speech.

As published in the Congressional Record Title bolded for clarity; it is not bolded in the source file.
                      Recognizing Curtis Ferguson

  Mr. HILL. Mr. Speaker, I rise today to recognize the late Curtis
Ferguson of Benton, Arkansas.

=========================== NOTE ===========================
On September 18, 2024, page H5442, in the third column, the
following appeared: RECOGNIZING CRAIG FERGUSON Mr. HILL. Mr.
Speaker, I rise today to recognize the late Curtis Ferguson

The online version has been corrected to read: RECOGNIZING
CURTIS FERGUSON Mr. HILL. Mr. Speaker, I rise today to recognize
the late Curtis Ferguson
========================= END NOTE =========================

  Mr. Ferguson’s big personality and civic leadership left a big
impression on everyone he met. He was truly larger than life.
# … tribute continues …

Each half, as we stored it:

Statement 1
Recognizing Curtis Ferguson

Mr. Speaker, I rise today to recognize the late Curtis Ferguson of Benton, Arkansas.
=========================== NOTE ===========================
On September 18, 2024, page H5442, in the third column, the following appeared: RECOGNIZING CRAIG FERGUSON Mr. HILL. Mr. Speaker, I rise today to recognize the late Curtis Ferguson

The online version has been corrected to read: RECOGNIZING CURTIS FERGUSON Mr. HILL. Mr. Speaker, I rise today to recognize the late Curtis Ferguson

GPO note text
Statement 2
========================= END NOTE =========================

Mr. Ferguson’s big personality and civic leadership left a big impression on everyone he met. He was truly larger than life. Curtis passed away on June 16. Whether meeting Curtis in business, at church, or civic activities, you were smiling and glad he was helping.

END NOTE delimiter detected as the title

The fix

The pipeline fix for this case was easy. We added simple pre-processing logic to remove complete NOTE … END NOTE blocks from the full page text before the rest of processing runs. We also made the speaker-marker regex stricter, so a line like Mr. Ferguson’s is no longer treated as a byline.

Case 8: A section divider stored as statement text

In the Senate’s “Additional Statements” section, GPO prints a centered divider before each tribute. Usually that divider is a plain underscore rule (______), which our parser already recognizes and removes. On a small number of pages the divider instead comes through as the text F_____—a capital F followed by five underscores. We do not know exactly why GPO’s plaintext sometimes renders the divider this way; the likeliest explanation is a decorative print symbol that did not survive the conversion to plain text. Regardless it is not spoken content. We found the frequency of this printing quirk to be quite rare: across our roughly 50,000 statements the F_____ form appears only twice in the source text, both on a single page in the Senate’s “Additional Statements” section.

Our parser strips separator lines made only of underscores, but F_____ begins with a capital letter, so it does not match that rule and gets carried through as text. One example of this leak was Senator Kevin Cramer’s Tribute to Dale Dannewitz in the Senate on July 31, 2024. Under “Additional Statements,” a divider appears before each tribute—before Cramer’s tribute and again before Senator Tester’s Tribute to Katharine Berkoff. The F_____ does not trigger our title detection logic or any other special processing. Instead it is included as the last line of the statement, as it is followed by a title which our processing correctly detects, opening a new statement.

As published in the Congressional Record Titles bolded for clarity; they are not bolded in the source file.
                                 F_____

                       TRIBUTE TO DALE DANNEWITZ

  Mr. CRAMER. Madam President, it is an honor to recognize the
nearly half century of distinguished service of a remarkable North
Dakotan who retired this year.
# … tribute continues …
  It is people like Dale Dannewitz who have ensured the safe movement
of products and commodities across the continent by rail. On behalf of
all North Dakotans, I thank him for his service and congratulate him on
his well-earned retirement. May you enjoy many years of health and
happiness in the future.
                                 F_____

                      TRIBUTE TO KATHARINE BERKOFF

  Mr. TESTER. Madam President, I rise today to recognize an
outstanding Montanan ...

The second divider followed Cramer’s closing sentence, so it was stored as the tail of his statement:

As stored
Tribute to Dale Dannewitz

…It is people like Dale Dannewitz who have ensured the safe movement of products and commodities across the continent by rail. On behalf of all North Dakotans, I thank him for his service and congratulate him on his well-earned retirement. May you enjoy many years of health and happiness in the future. F_____

Leaked section divider stored as statement text

The fix

A full-corpus scan of nearly 50,000 loaded statements found this in exactly one statement. We stripped the trailing token by hand and chose not to change the pipeline for something this rare. We will re-scan periodically and fix by hand.

Case 9: Wrong speaker (or no speaker) from a byline typo

GPO sometimes prints a speaker byline with a typo: no punctuation after the name, or a title-case surname where the Record usually uses all caps. Our matcher misses that line. If the previous file still has a speaker, we reuse it and store the tribute under the wrong member. If there is no speaker to reuse, the tribute never loads.

Case 9a: No punctuation before “Mr. Speaker”

The canonical byline GPO prints is an all-caps name followed by a period, then the chair address: Mr. SMITH. Mr. Speaker, I rise …. We found a small number of cases where GPO appears to have misprinted the byline and left that period out.

As published — Extensions of Remarks, November 8, 2023 PgE1077 — Honoring River Rock Outfitter
                     HONORING RIVER ROCK OUTFITTER

                                 ______

                     HON. ABIGAIL DAVIS SPANBERGER

                              of virginia

                    in the house of representatives

                      Wednesday, November 8, 2023

  Ms. SPANBERGER Mr. Speaker, I rise to congratulate April and Keith
Peterson and the River Rock Outfitter team on their hard-earned
nomination for the United States Chamber of Commerce's 2023 Top Small
Business award.
# … tribute continues …

There is no period after SPANBERGER. Our speaker-line matcher did not treat this as a byline opening. The previous Extensions page that day had ended with a tribute by Representative Blaine Luetkemeyer; carryover reused his speaker label for Spanberger’s text. We stored the full tribute under Luetkemeyer’s name, with Ms. SPANBERGER still embedded at the start of the statement body.

As stored (wrong)
Honoring River Rock Outfitter

Speaker: Blaine Luetkemeyer (Missouri)
Ms. SPANBERGER Mr. Speaker, I rise to congratulate April and Keith Peterson and the River Rock Outfitter team on their hard-earned nomination…

Wrong member; byline prefix leaked into statement text

Case 9b: Title-case surname on the byline

E-page bylines usually print the surname in all caps (Ms. TLAIB. Mr. Speaker, …). Occasionally GPO uses title case instead. Our byline matcher expects an all-caps surname (with narrow prefix exceptions for names like DeLAURO and McGOVERN). A title-case line does not match.

As published — November 21, 2023 PgE1119-2 — Recognizing Hume G. Merritt
                      RECOGNIZING HUME G. MERRITT

                                 ______

                           HON. RASHIDA TLAIB

                              of michigan

                    in the house of representatives

  Ms. Tlaib. Mr. Speaker, today I want to recognize long-time resident
and veteran Hume G. Merritt, as he is joined by his family and well-
wishers as he celebrates his eightieth birthday.
# … tribute continues …

The same member’s other tributes that day used Ms. TLAIB. and loaded normally. This file was the first Extensions page in that day’s package, so there was no carryover speaker to fall back on. Every speech line was skipped. We detected the topic title Recognizing Hume G. Merritt but stored zero statements and wrote no row to the database.

The fix

These failures are load-time corruption: wrong person_id or missing tributes. We plan to fix them in the parser rather than rely on post-load detection alone.

On Extensions pages, the parser now also accepts two byline shapes the main matcher missed. If an all-caps name is followed immediately by Mr. Speaker, with no period, we treat that line as a byline. If the surname is in title case and a period and chair address follow (Ms. Tlaib. Mr. Speaker, …), we treat that as a byline too.

After each monthly load, a residual-speaker check scans stored statement text for a byline the parser should have consumed, such as Ms. SPANBERGER still sitting in the body. Findings go into the day’s validation report. Review agents then run automatically, read the report, and apply repairs.

Case 10: An untitled speech inherits the wrong title

A speech can be stored under the wrong title even when every heading on the page is printed correctly and detected correctly. For example, on January 20, 2022, Representative Colin Allred was recognized for 60 minutes on voting rights. He yielded to colleagues, then took the floor back. GPO printed a heading when each guest started a new subject. GPO did not reprint Voting Rights when Allred resumed. Our rule assigns a statement to the most recent heading, so his voting rights speech inherited Infrastructure, the last topic before he resumed.

He yielded first to Representative Correa for a tribute to Manuel T. Padilla, then to Representative Foster, who spoke under Brandon Road Project and then Infrastructure. When Allred took the floor back, there was no new heading. He thanked Foster and opened with “I am here today to talk about the foundation of our democracy: the right to vote.” Those 3,481 words were stored under Infrastructure. The headings run in this order:

CREC-2022-01-20-pt1-PgH273-6.htm — headings
                             VOTING RIGHTS

  The SPEAKER pro tempore (Mr. Kahele). Under the Speaker's announced
policy of January 4, 2021, the gentleman from Texas (Mr. Allred) is
recognized for 60 minutes as the designee of the majority leader.

                             General Leave

  Mr. ALLRED. Mr. Speaker, I ask unanimous consent that all Members
have 5 legislative days to revise and extend their remarks and include
extraneous material on the subject of my Special Order.
# … speech continues …

           Honoring the Life and Memory of Manuel T. Padilla

  Mr. CORREA. Mr. Speaker, today we honor the life and memory of Manny
T. Padilla, a leader in our community and my very, very good friend.
# … tribute continues …

                          Brandon Road Project

  Mr. FOSTER. Mr. Speaker, I rise today to share some great news about
our efforts to protect Lake Michigan and the rivers and lakes
throughout Illinois and the entire Great Lakes region from invasive
Asian carp.
# … speech continues …

                             Infrastructure

  Mr. FOSTER. Mr. Speaker, for decades, Americans have been asking
their elected leaders to fix crumbling roads and bridges and modernize
our Nation's transportation infrastructure.
# … speech continues …
  I have to say, I look forward to meeting my Republican colleagues at
the ribbon cutting ceremonies for all of these projects that they voted
against.
  Mr. ALLRED. Mr. Speaker, I thank the gentleman for his comments.
  Mr. Speaker, I am here today to talk about the foundation of our
democracy: the right to vote and why we must protect it.
# … speech continues …
No new heading; inherits Infrastructure

Foster's infrastructure remarks end. Allred then takes his own time back and delivers the speech the hour was called for. There is no heading between them, because GPO does not print one.

Our rule is that a statement belongs to the most recent heading. The most recent heading is Infrastructure, so that is where 3,481 words about the right to vote were filed.

The Voting Rights heading is still on the page. Under it are the Chair recognizing Allred, his general-leave request, and the yield to Correa. None of that is the speech. The speech is stored under Infrastructure, so a reader looking for voting rights does not find it.

This case is not a split or a duplicate. Allred's speech is one statement of 3,481 words, stored once. The consent request, two yields, and the yield-back are separate procedural turns. The number of topics our processing extracts from the file is right. Only the title on Allred's speech is wrong. That is why this is its own case rather than another variant of Case 1.

The fix

Detecting this case in the core pipeline is difficult. It would take an LLM reading the title and the statement and deciding they do not match, and that would mean a model call on many statements. We chose not to do that.

Instead, after a load, we embed the stored title and the statement and measure their semantic similarity using text-embedding-3-large from OpenAI. That produces a score between −1 and 1. When the title and its content score low, they are dissimilar, as with Allred's voting-rights remarks stored under Infrastructure. Those pairs go into the day's validation report. Review agents then run automatically, read the report, and apply repairs.

A coda

This post is a fraction of the issues we found. The Record still prints cases our parser does not catch. Many of them are GPO layout and typos. GPO printed Representative Abigail Davis Spanberger's November 1, 2023 tribute to Mrs. Eileen Thrall with no period at the end of the opening paragraph. On the same day, GPO printed Representative Mariannette Miller-Meeks's title Congratulating Dennis Lauver as body text. On November 13, 2023, GPO printed Representative Ben Cline's byline as Mr. CLINE MEMBER. instead of Mr. CLINE. We have catalogued those and other cases in A Dictionary of Congressional Record Formatting Problems.

This is one reason we moved to a validation approach with LLM agents rather than trying to chase a seemingly near-infinite list of one-off issues and update them in the pipeline directly. We are currently writing a post that discusses that approach in more detail.