Part of RAG & Vector Databases — retrieval-augmented generation and vector search.
clean_filings.py and corpus_stats.py · 33 NVIDIA filings downloaded from SEC EDGAR · token counts taken from the serving model’s own tokenizer (Qwen3.8-27B on llama-server) · measured 2026-08-19. Nothing here is estimated.
Running RAG on SEC filings punishes a pipeline that looked perfect on demo PDFs. However, the reason is not document length. Rather, the reason is that a single answer rarely sits in a single place: it is split between a table and the paragraph explaining it, between a footnote and the line it qualifies, and between filings published two years apart. This article measures that dispersion on a real corpus of 33 NVIDIA documents, names the eight patterns it produces, and shows how to build the same corpus for your own documents. Every filing referenced here is linked in full under source documents.
- The NVDA-RAG-40 corpus holds 33 SEC filings and 749,859 tokens, spanning 2023-11-21 to 2026-07-02.
- Of 913 multi-row tables in these filings, exactly 2 have the same cell count in every row — 70.4% disagree between their own data rows.
- NVIDIA’s fiscal 2024 diluted EPS appears in this corpus as both $11.93 and $1.19, because a ten-for-one stock split in June 2024 retroactively restated every per-share figure.
- Raw SEC filings are 85.3% markup by volume; the readable text is the remaining 14.7%.
- Knowledge dispersion falls into eight repeatable patterns, four of them inside one document and four of them between documents.
What sits inside the NVDA-RAG-40 corpus
The corpus covers one company across three fiscal years. NVIDIA works well as a subject for a retrieval benchmark, because its filings are long, numerically dense and heavily cross-referenced. Moreover, every document comes from SEC EDGAR, the public filing system of the U.S. Securities and Exchange Commission.
Altogether four filing types appear, and each contributes a different kind of difficulty. Annual reports (10-K) carry the audited financial statements. In addition, quarterly reports (10-Q) repeat the same metrics at a finer granularity. Proxy statements (DEF 14A) hold governance and compensation data that never appears anywhere else. Finally, current reports (8-K) announce events, usually without quantifying them.

| Filing type | Documents | Median tokens | Total tokens | Why it is in the corpus |
|---|---|---|---|---|
| 10-K | 3 | 82,596 | 249,700 | Audited annual figures, FY2024–FY2026 |
| 10-Q | 8 | 42,342 | 330,487 | Quarterly granularity for the same metrics |
| DEF 14A | 2 | 72,122 | 138,611 | Governance data absent from every other form |
| 8-K | 20 | 1,277 | 31,061 | Event announcements that later filings quantify |
In practice, the size spread matters more than the total. As a result, a 10-K is roughly 65 times an 8-K, so any retriever that ranks by similarity alone will drown the short documents. Therefore the corpus deliberately keeps 20 small 8-K filings against 3 large 10-K filings.
Why RAG on SEC filings starts with 85% markup
To begin with, SEC filings are not PDFs, and they are not plain HTML either. They arrive as Inline XBRL: machine-readable accounting tags embedded inside the presentation markup. As a result, a raw filing is mostly scaffolding. Across this corpus, 85.3% of the raw bytes are markup, and the readable text is the remaining 14.7%.
Moreover, that scaffolding is where most pipelines quietly lose data. Meanwhile, a naive text extraction returns prose in which every financial table has collapsed into a run of loose numbers. The digits survive, although the row labels and the column headers do not, so the number stops meaning anything.
Consequently the conversion step deserves real attention. Specifically, our converter drops the hidden XBRL context block, renders each table as a Markdown pipe table, and promotes Item 1A. style lines to headings so the section structure survives into the chunker. It runs on the standard library plus BeautifulSoup:
# 1) Download the filings from SEC EDGAR (stdlib only, writes SHA-256 manifest)
python benchmark/corpus/download_edgar.py
# 2) Inline XBRL -> Markdown, preserving tables and Item structure
python benchmark/corpus/clean_filings.py
# 3) Measure the corpus (exact tokens via llama-server /tokenize)
python benchmark/corpus/corpus_stats.py
All five scripts, plus the chart and screenshot generators and the measured JSON behind every figure here, are packaged together: download the corpus pipeline (ZIP). Unzip it and the commands above run as written, because the folder layout matches the paths.
Eight ways RAG on SEC filings loses the answer
In short, dispersion is not one problem. Instead it is eight, and they fail differently. Four patterns keep the knowledge inside a single document, while four scatter it across documents. Furthermore, naming them matters, because a framework that solves one may be helpless against another.
| ID | Pattern | Scope | Evidence in this corpus |
|---|---|---|---|
| D1 | Table vs narrative split | Within a document | Tables are only 13.3–13.9% of a 10-K’s characters |
| D2 | Footnote dependency | Within a document | 311 “Note N” references across the corpus |
| D3 | Definition-then-use distance | Within a document | 530 “Item N” cross-references |
| D4 | Granularity mismatch | Between documents | 8 quarterly filings against 3 annual ones |
| D5 | Event then consequence | Between documents | 20 8-K filings, zero footnote references |
| D6 | Governance vs operations | Between documents | 2 DEF 14A filings, 72,122 median tokens |
| D7 | Retroactive restatement | Between documents | FY2024 EPS reported as $11.93 and $1.19 |
| D8 | Absence | Corpus-wide | Questions with no supporting evidence |
For that reason, the sections below walk the patterns that do most of the damage in practice. Each one comes with the measurement that proves it exists in this corpus.
D1: why RAG on SEC filings misreads tables
Financial tables look like grids. However, they are laid out for print rather than for parsing. A currency row spends separate cells on the dollar sign and the closing parenthesis; a percentage row does not. As a result, the same visual column lands on a different cell index depending on the row.
Therefore we measured this on the source markup of all 33 filings. In total, out of 913 multi-row tables, only 2 keep a consistent cell count across every row. In 643 tables — 70.4% — the data rows disagree with each other, not merely with the header. Worse still, one table in the FY2026 annual report contains rows of nine different widths.
In other words, this is what it looks like in the filing itself. Notice how the dollar sign occupies its own cell on the Revenue and Net income rows, yet disappears on the rows between them.
Free ebook
Free AI Video, Generated Locally
Working scripts and measured benchmarks. Free.
No spam. Unsubscribe at any time.

Therefore, keeping such a table usable means dropping the spacer columns rather than the data. Consequently a column survives only when at least one row puts something meaningful in it:
# A cell that carries no information: currency symbols, spacers, rules.
NOISE_CELL_RE = re.compile(r"^[s$%()—–.:,* |-]*$")
# Drop a column only when every row agrees it is noise.
keep = [c for c in range(width)
if not all(NOISE_CELL_RE.match(r[c]) for r in rows)]
rows = [[r[c] for c in keep] for r in rows]

Importantly, the count itself comes from the source markup, not from our converted copy, because conversion normalises the very geometry we want to measure:
counts = [len(tr.find_all(["td", "th"]))
for tr in table.find_all("tr") if tr.find_all(["td", "th"])]
if len(set(counts)) == 1: # every row agrees
uniform += 1
elif len(set(counts[1:])) == 1: # only the header differs
header_only += 1
else: # data rows disagree with each other
body_ragged += 1
D2: the footnote that changes the number
Similarly, a figure in a financial statement is frequently qualified elsewhere. In practice, the corpus contains 311 explicit “Note N” references, concentrated in the quarterly reports (196) and annual reports (107). In effect, each one is a pointer from a number to the text that gives it conditions.
A chunker typically splits the table and its note into different chunks, and a retriever then returns only one of them. As a result, the answer looks correct while remaining quietly incomplete. Note that the 8-K filings contain zero footnote references, which is precisely why they cannot answer quantitative questions on their own.

D4, D5 and D6: the answer lives in another document
Three patterns move the answer out of the document entirely. First, granularity mismatch (D4): a question about an annual figure may require summing four quarterly reports, or reconciling them against the audited annual one. This corpus holds 8 quarterly filings against 3 annual filings precisely so that reconciliation is testable.
Second, the event-then-consequence pattern (D5). An 8-K announces something — a leadership change, a buyback authorisation, a material agreement — and a later 10-K or 10-Q quantifies its effect. However, the 8-K filings here carry a median of just 1,277 tokens and, as noted, zero footnote references. In other words, they are pointers rather than sources.
Third, governance sits apart from operations (D6). Executive compensation, board composition and shareholder proposals appear only in the DEF 14A proxy statement, which contributes 72,122 median tokens but only 8 footnote references. Consequently a question about pay ratios cannot be answered from any 10-K, no matter how good the retriever is.
These three patterns share a failure signature. The retriever returns a confident, well-formed chunk from the wrong document class, because that chunk is topically similar. Therefore recall@k measured on a single document type systematically overstates how well a framework will perform.
D3 and D7: the answer that expired
By contrast, the sharpest failure in this corpus is not a missing number. It is a stale one. In June 2024 NVIDIA executed a ten-for-one stock split, so every per-share figure filed before that date was retroactively divided by ten in later filings.
To confirm this, our extraction script pulled the diluted EPS row from all three annual reports. Fiscal 2024 diluted EPS appears as $11.93 in the 10-K filed on 2024-02-21, and as $1.19 in the 10-K filings from 2025 and 2026. Likewise, the diluted share count moved the same way, from 2,494 million to 24,940 million. Fiscal 2023 shows the identical pattern, at $1.74 against $0.17.


Building a RAG corpus from your own documents
Fortunately, the method transfers to any regulated or versioned document set: contracts, clinical protocols, engineering specifications. First of all, choose one entity and a time span long enough to contain at least one revision. Second, gather more than one document type, because single-type corpora hide the between-document patterns entirely.
Next, convert with the tables intact and record a SHA-256 manifest, so a re-run is verifiable. After that, measure before you build anything: token counts, table geometry, cross-reference density. Finally, walk the eight patterns above and mark which ones your corpus actually exhibits. A corpus lacking D7 cannot test whether a framework handles superseded facts.
Finally, one practical note on scale. For instance, a 10-K in this corpus is roughly 82,600 tokens, so two full annual reports fit simultaneously inside the 204,800-token context window we serve. That capacity is what makes automated cross-document question extraction possible, which is the subject of the next episode.
Why this RAG corpus is test material, not investment advice
In summary, these documents were chosen because they are public, stable, numerically rich and awkward to retrieve from. Therefore the benchmark measures retrieval systems, not NVIDIA. No statement in this series is a claim about the company’s prospects, and no figure here should inform a financial decision. Anyone needing NVIDIA’s actual numbers should read the filings directly on SEC EDGAR.
Frequently asked questions
What is the hardest part of RAG on SEC filings?
Dispersion, not length. A single answer is typically split across a table, its footnote and a narrative paragraph, and often across two filings published a year apart. Retrieving the right document is rarely the failing step.
How many documents does a RAG benchmark corpus need?
Fewer than people expect, provided that the types vary. This corpus uses 33 documents and 749,859 tokens, but it spans four filing types and three fiscal years, which is what produces the between-document patterns.
Why not just use the XBRL tags instead of the text?
Because the tags answer only numeric questions on their own. Governance facts, risk-factor language and event narratives carry no XBRL tagging, and roughly 86% of a filing’s raw volume is markup that contains no prose at all.
Do SEC filings really change after publication?
Yes — per-share figures do, routinely. NVIDIA’s ten-for-one split in June 2024 restated fiscal 2024 diluted EPS from $11.93 to $1.19 across later filings, and both versions remain publicly available.
Which tokenizer produced these token counts?
The counts come from the /tokenize endpoint of llama-server running Qwen3.8-27B-UD-Q4_K_XL, the same model used throughout this series. Token counts differ between tokenizers, so a count is only meaningful next to its model.
Can I reproduce this corpus exactly?
Yes. The download script records a SHA-256 manifest for every filing, so a later run can verify byte-for-byte that it fetched the same documents from SEC EDGAR.
Summary
The NVDA-RAG-40 corpus contains 33 SEC filings and 749,859 tokens, covering 2023-11-21 to 2026-07-02. Its raw bytes are 85.3% markup. Of its 913 multi-row tables, just 2 are cleanly rectangular, and 70.4% have data rows that disagree with each other. Above all, it contains a genuine retroactive restatement: fiscal 2024 diluted EPS reads $11.93 in one annual report and $1.19 in the next two.
Above all, those properties are the point. A corpus without them tests nothing that production data will throw at a retriever. In the next episode we turn this corpus into a golden set, using the long context window to extract questions that genuinely require combining documents.
The eight dispersion patterns above are what that extraction targets, one pattern at a time. The golden-set episode publishes the complete prompt for each of them, together with the structural rule that decides whether a proposed question really exhibits its pattern.
Further reading on why structural chunking beats paragraph chunking for financial documents: Financial Report Chunking for Effective Retrieval Augmented Generation.
Source documents for RAG on SEC filings
In short, every number above traces back to one of the 33 filings listed here. Furthermore, each row links to the document exactly as NVIDIA filed it, so any claim in this article can be checked at the source. Note also that token counts come from the serving model’s own tokenizer.
Periodic and proxy filings
Together, these 13 documents carry the audited figures, the footnotes and the governance data. Consequently they supply most of the evidence for the dispersion patterns above.
| Form | Filed | Tokens | Document on SEC EDGAR |
|---|---|---|---|
| 10-Q | 2023-11-21 | 45,008 | nvda-20231029.htm |
| 10-K | 2024-02-21 | 82,596 | nvda-20240128.htm |
| 10-Q | 2024-05-29 | 38,658 | nvda-20240428.htm |
| 10-Q | 2024-08-28 | 43,711 | nvda-20240728.htm |
| 10-Q | 2024-11-20 | 42,342 | nvda-20241027.htm |
| 10-K | 2025-02-26 | 84,829 | nvda-20250126.htm |
| DEF14A | 2025-05-13 | 72,122 | nvda-20250512.htm |
| 10-Q | 2025-05-28 | 37,455 | nvda-20250427.htm |
| 10-Q | 2025-08-27 | 40,962 | nvda-20250727.htm |
| 10-Q | 2025-11-19 | 44,068 | nvda-20251026.htm |
| 10-K | 2026-02-25 | 82,275 | nvda-20260125.htm |
| DEF14A | 2026-05-12 | 66,489 | nvda-20260512.htm |
| 10-Q | 2026-05-20 | 38,283 | nvda-20260426.htm |
Current reports
Meanwhile, the 20 8-K filings announce events as they happen. Individually they are tiny, yet they are what makes the event-then-consequence pattern testable.
| Form | Filed | Tokens | Document on SEC EDGAR |
|---|---|---|---|
| 8-K | 2024-11-07 | 1,230 | nvda-20241107.htm |
| 8-K | 2024-11-20 | 1,269 | nvda-20241120.htm |
| 8-K | 2025-01-17 | 1,958 | nvda-20250113.htm |
| 8-K | 2025-02-26 | 1,277 | nvda-20250226.htm |
| 8-K | 2025-03-07 | 1,485 | nvda-20250303.htm |
| 8-K | 2025-04-15 | 1,360 | nvda-20250409.htm |
| 8-K | 2025-05-28 | 1,268 | nvda-20250528.htm |
| 8-K | 2025-07-01 | 3,190 | nvda-20250625.htm |
| 8-K | 2025-08-05 | 976 | nvda-20250731.htm |
| 8-K | 2025-08-27 | 1,268 | nvda-20250827.htm |
| 8-K | 2025-11-19 | 1,268 | nvda-20251119.htm |
| 8-K | 2026-01-23 | 972 | nvda-20260120.htm |
| 8-K | 2026-02-25 | 1,270 | nvda-20260225.htm |
| 8-K | 2026-03-06 | 1,497 | nvda-20260302.htm |
| 8-K | 2026-04-27 | 1,492 | nvda-20260424.htm |
| 8-K | 2026-05-08 | 1,240 | nvda-20260507.htm |
| 8-K | 2026-05-20 | 1,270 | nvda-20260520.htm |
| 8-K | 2026-06-18 | 2,348 | d48176d8k.htm |
| 8-K | 2026-06-30 | 2,877 | nvda-20260624.htm |
| 8-K | 2026-07-02 | 1,546 | nvda-20260628.htm |
Finally, the full filing history sits on NVIDIA’s SEC EDGAR company page. Because the download script records a SHA-256 hash for every file, a later run can prove it fetched exactly these documents.
Companion code — the fragments above are the working parts of the pipeline: the noise-column filter that keeps financial tables readable, and the row-width check behind the raggedness count. Everything runs from one archive — nvda-rag-e01-corpus-scripts.zip — which also carries the measured JSON, so the charts rebuild without re-downloading a single filing.
Free ebook
Free AI Video, Generated Locally
Run Wan 2.1 in ComfyUI on your own GPU — the scripts I use, measured times, sample clips. No cloud, no API keys.
No spam. Unsubscribe at any time.


Leave a Reply