# Changelog of Government PDF Table Extractor – PDF to JSON (`lwsdjfls/govt-pdf-table-extractor`) Actor

- **URL**: https://apify.com/lwsdjfls/govt-pdf-table-extractor/changelog.md
- **Full Actor documentation**: https://apify.com/lwsdjfls/govt-pdf-table-extractor.md

## Changelog

### 0.1

- Initial release: deterministic table extraction (Camelot 2.0 stream and lattice, pdfplumber ruled lines) with caption, header and footnote separation, group labels spread over their columns, wrapped row labels re-joined, tables joined across pages, Dutch and English number parsing, column types, sum checks and confidence; optional Claude Haiku 4.5 / Sonnet 5 pass for scanned pages and low-confidence tables, validated by the same code.
- Hardened for untrusted input: only http(s) PDF URLs of at most 2,048 characters; the same file twice (a repeated URL, a mirror serving identical bytes, or an upload of a linked file) is read and charged once and gets a `duplicate` document record; after 20 documents that cost nothing (failed downloads, repeats, PDFs that cannot be opened, documents too large for the run's memory, no page to process), or once the spending limit is reached, the remaining documents are not tried; an LLM page whose answer cannot be used still counts in the document record; `maxFileMb` is at most 100; `pages` is at most 1,000 characters and checked with a pattern that runs in linear time, and reaches the PDF worker without spaces; a download larger than `maxFileMb` is refused as soon as its size is known; cell text is whitespace-normalised and capped at 2,000 characters before parsing; uploaded files (`pdfFiles`) are delivered again, with the Actor page as source link.
- LLM pages: charged as soon as the model has answered; answers capped at 4,096 output tokens; expected columns sent as a bounded data list; a run stops sending pages to the model when its API cost runs far above what its LLM pages are charged.
- The PDF worker runs with a minimal environment (no API keys or tokens); its Python dependencies are pinned with their whole dependency closure and hash-checked.
- Tables larger than one dataset item (about 8 MB) are delivered in consecutive parts with a `part` field (shown in the `tables` view) and charged once; a table lists at most 100 sum checks, 100 warnings and 100 footnotes (20,000 characters), so what each part repeats stays small and the parts follow the table's real size; a table that cannot be delivered even in parts (only a crafted file) is counted in the document's `tablesNotDelivered` and named in its `error`; a run holds at most 32 MB of tables per GB of memory and reads at most about 21 MB of worker output per document per GB, and a document over either limit fails on its own, free of charge, instead of the whole run failing with nothing delivered (its error says when no run with this memory can hold it, and in the LLM modes a document whose tables on the pages the model does not read are already too large sends no page to the model); validating a long table takes time in proportion to its cells (sum checks keep running totals instead of re-adding every row above each total), and headers and footnotes of crafted tables are joined in linear time.
- Each document's file and page images are deleted as soon as it is done, and pages are rendered for the LLM ten at a time; a file that cannot be stored fails only that document, and a full disk stops the remaining documents.
- A PDF the worker cannot open gets a failed document record with the exception (without the worker's command line, traceback frames or file paths) and the LLM pages already read; the pages it reserved but did not charge go back to the run's LLM page cap and spending limit.
- `cells` of a table joined across pages cover every page and carry their page number, and are not built at all when `includeCells` is off; `flavor: lattice` keeps the tables of pdfplumber's ruled-line reader it runs.
- File names from Content-Disposition, the URL or `pdfFiles` are cleaned of control characters and cut to 200 characters, and go into the LLM prompt as a quoted string.
