# What survives résumé text extraction?

Guul controlled extraction study, version 1. Prepared October 2, 2026.

## Scope

Ten fictional English-language profiles, two layouts, two formats. That is **40 files**,
not 40 independent people or 40 Guul templates. Names, organizations and histories are fictional.
Every file is marked as a research fixture. Emails use example.com and telephone numbers use
the reserved US 555-01xx range, including fixtures with non-US locations.

The 20 PDFs are read by PDF.js, Poppler and PyMuPDF. The 20 Word documents are read by Mammoth.
That makes **80 extractions**. These are extraction libraries, not connections to employer ATS
products. The study does not test the Guul résumé import pipeline, competitors' products,
application rejection, writing quality, bias or interview outcomes.

PDFs use A4, one vendored Inter font, Chromium and two controlled HTML layouts. DOCX files use
A4 and Arial, with paragraphs for the single-column layout and a table for the sidebar. Mammoth
reads document XML; Word files are not visually rendered in this study. These differences mean
the results are **not a controlled ranking of PDF versus Word**. No image-only files, OCR,
real customer files, multilingual prose or right-to-left scripts are included.

## Measurements

Each document has eleven expected whole fields. The scorer normalizes case, Unicode NFKC,
apostrophes, dash variants and whitespace. It requires the normalized phrase to appear
contiguously and be bounded, so a field interrupted by another column fails even when all its
individual words remain present. It does not remove private-use Unicode characters or repair
substituted glyphs. Field recovery is not semantic understanding.

The declared section order is Professional Summary → Work Experience → Education → Technical
Skills. In a sidebar, this means finish the main column, then the sidebar. This is a disclosed
test convention, not the only acceptable human reading path. Order checks use four heading
markers; they do not prove all sentences or field associations are correct.

Library settings are recorded in results.json. PDF.js joins returned items with spaces and
uses explicit line endings. The browser diagnostic uses a different adapter that also looks at
visible gaps between text runs. Do not describe the two outputs as byte-for-byte identical.

This is one run per file/engine. There are no confidence intervals or population estimates.
All ten profiles share a generator and font. A failure can be specific to that export/font/
library combination. This is a small regression fixture set, not a general parser leaderboard.

## Reproduce

The downloadable bundle contains the measured sources, fixture inputs, reference outputs,
font, font notice and pinned Node dependencies. No customer data is used.

1. Install Node (the recorded run uses Node 24.10.0) and Python 3.
2. Install Poppler's `pdftotext`. The recorded version is 26.07.0. Use your platform's package
   manager or build that version. A different version is a new experiment, not an exact replay.
3. In the bundle directory, run `npm ci` and `npx playwright install chromium`.
4. Create a Python environment and install `python3 -m pip install -r requirements.txt`.
5. Run `node --test metrics.check.mjs`, then `node run.mjs ./rerun-results`.
6. Compare `rerun-results/results.json` with `reference/results.json`, including the versions,
   missing fields and section order for each file/engine. Raw text outputs are included.

Installing dependencies needs internet access. Rendering and extraction make no external
network requests. The script fails rather than fabricating results if a required tool is absent.
PDF/DOCX byte hashes can differ across runs because of document timestamps and ZIP metadata.
Use the supplied reference files when reproducing the exact bytes.

Within the Guul checkout, run from its root:

```sh
node --test scripts/research/metrics.check.mjs
node scripts/research/run.mjs /tmp/guul-study-results
python3 scripts/research/package.py /tmp/guul-study-results
node scripts/research/verify.mjs
```

Packaging is an explicit publication update. It checks that the measured source hashes match
the files being bundled and refuses to package edited sources over old results. Do not overwrite
an earlier dated publication with a changed method; create a new dated version.

## Reuse and citation

The original fictional fixture data and measurement tables in this study are available under
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Credit Guul, link to
https://guul.io/resume-template-parse-tests#extraction-study, give the run timestamp from
results.json, and describe any changes. The small study scripts are provided under the MIT
license in LICENSE. Third-party dependencies keep their own licenses. The Inter font keeps
its SIL Open Font License; see FONT-LICENSE.txt.

Suggested citation: Guul. _What survives résumé text extraction?_ Version 1. Run timestamp and
library versions in the accompanying dataset. Ten fictional profiles, 40 files, 80 extractions.

Corrections should identify the fixture, library/version, observed text and expected field.
Do not submit a real person's résumé as a public example.
