LUCERIA
Method v1.0.0 · measured 4 November 2026

Document repair lab: five one-change fixes, measured before and after

In five one-change repairs of one synthetic resume, rebuilding two columns or a layout table as one column raised Luceria's reading-order score from 54.5% to 95.5%; moving the contact line from a Word page header into the body made the email and phone readable; removing a running header cleared the repeated-contact flag; and a PDF whose text was drawn as outlines went from refused, with no text layer, to fully read once it was exported as real text. Token recall was already complete in three of the five before files, so most repairs change order and fields rather than whether the words are found.

Watch it

Results

Environment: Node v24.16.0 on Windows x64; lib/extract.ts with pdf-parse 2.4.5 (PDF) and mammoth 1.12.0 (Word); fixtures generated with docx 9.6.1, pdfkit 0.18.0 and fontkit 2.0.4; one run.

Fixtures measured
12
Two controls and five before/after pairs of one fictional resume.
Repairs measured
5
Each changes one stated variable.
Reading order, two columns to one column (PDF)
54.5% → 95.5%
The remaining gap is the stacked contact details, which never match the single expected contact line.
Reading order, layout table to one column (Word)
54.5% → 95.5%
Same content and styles; the table cells were read sidebar first.
Email and phone readable, header to body (Word)
no → yes
The page header was not extracted, so contact details placed only there were lost.
Repeated-contact flag, running header removed (PDF)
raised → not raised
Text recall was complete either way; the header only duplicated the contact line.
Text extracted, outlines to real text (PDF)
refused → 100.0% token recall
The outlined file has no text layer, so the extractor refused it instead of returning an empty result.
Fixture hashes reproduced by --verify
12 of 12
Same machine, separate processes and two time zones; another machine not yet tested.
Repairs (method 1.0.0, measured 4 November 2026)
RepairSymptomVariable changedToken recallReading orderEmail / phoneFlags removed
r1order-jumbledColumn layout: two columns drawn as two text streams → one column in reading order100.0% → 100.0%54.5% → 95.5%yes / yes → yes / yesnone
r2order-jumbledDocument structure: a two-cell layout table → the same paragraphs in one column in reading order100.0% → 100.0%54.5% → 95.5%yes / yes → yes / yesnone
r3contact-missingContact location: page header → document body95.5% → 100.0%95.5% → 100.0%no / no → yes / yesnone
r4duplicate-textRunning header: contact line repeated on every page → none (contact once in the body)100.0% → 100.0%100.0% → 100.0%yes / yes → yes / yesrepeated-contact
r5empty-or-imageText layer: glyph outlines with no text objects → real text at the same positions0.0% → 100.0%0.0% → 100.0%no / no → yes / yesnone
Fixtures with SHA-256 prefixes (full hashes in manifest.json)
FixtureRoleExtractedToken recallReading orderEmail / phoneSHA-256
control-docxcontrolyes100.0%100.0%yes / yesadba30f38b3d
control-pdfcontrolyes100.0%100.0%yes / yes089a0aefdae0
r1-beforebeforeyes100.0%54.5%yes / yese26a9e2e18b1
r1-afterafteryes100.0%95.5%yes / yes1f812df5eab2
r2-beforebeforeyes100.0%54.5%yes / yes93c6be019f71
r2-afterafteryes100.0%95.5%yes / yesebfaa47a2e95
r3-beforebeforeyes95.5%95.5%no / no55e47ffdef72
r3-afterafteryes100.0%100.0%yes / yesadba30f38b3d
r4-beforebeforeyes100.0%100.0%yes / yes2c25030556a0
r4-afterafteryes100.0%100.0%yes / yes2c3ff223cc6d
r5-beforebeforeno (no text layer)0.0%0.0%no / no8def9a235951
r5-afterafteryes100.0%100.0%yes / yes62ee08b2c4e9

Method

Fixtures

Twelve synthetic files of the same fictional resume used by the parser benchmark: one Word and one PDF control, and five before and after pairs. Each pair changes exactly one stated variable: column layout, a layout table, where the contact line sits, a running header, or whether the text exists as text at all. In the column and table repairs the sidebar sections move into reading order, because that is what rebuilding in one column means.

The text-layer pair draws the same lines with the same embedded font (Liberation Sans, SIL Open Font License) at identical positions, once as filled glyph outlines with no text objects, the way a scan or an outlined export looks to a parser, and once as real text.

Extraction and measures

Each file is read by lib/extract.ts, the extractor behind Luceria's upload route (pdf-parse for PDF, mammoth for Word). Token recall, reading order, bullets, headings and contact readability are computed by the same code as the parser benchmark (scripts/research/shared/measure.ts), and the layout flags come from the parser preview tool's heuristics. A file the extractor refuses for having almost no text is recorded as refused, not scored as an empty pass.

Reproducibility

PDF metadata dates are fixed and Word files are re-packed with fixed archive dates, so the recorded library versions produce byte-identical files. The manifest lists every file's SHA-256 hash, the generator and parser versions and their licences, and the font file's hash. Running the lab with --verify regenerates every file in memory and compares hashes and measures with the published copies; it reproduced all twelve in separate processes and under a second time zone on the measuring machine. Another machine has not yet been tested.

Limitations

  • One fictional resume and twelve synthetic files. Each repair changes one stated variable; real documents combine several problems and vary in fonts and authoring software.
  • This measures Luceria's own extractor. It does not test any employer's applicant tracking system, which may use a different parser with different behaviour, and it cannot predict hiring outcomes.
  • Outlined text stands in for scans and photographs: a parser without optical character recognition, which Luceria does not run, treats them the same way.
  • Reading order uses the parser benchmark's measure, which credits a line the extractor split in two when a fragment holds more than 30 characters of it; scored strictly on whole lines the figures could be lower, and this study does not publish its extracted text. Contact details stacked on three lines never match the single expected contact line, so the after scores for the column repairs stop at 95.5 percent.
  • Hashes are reproducible with the recorded library versions only; a different version of docx, pdfkit, fontkit or JSZip may produce different bytes with the same text.

Corrections

None so far. Spotted an error? Tell us and it will be checked against the data and recorded here.

Related documentation

Common questions

Will these fixes make an employer's system read my resume?

They remove the specific problems measured here for Luceria's parser. Employer systems use different parsers, so check your own file with the parser preview and, where an employer documents its own upload rules, follow those.

Why change only one thing per repair?

So the measured difference belongs to that change. Real files often combine problems; fix them one at a time and re-check after each.

Published 6 November 2026 · Results are generated by code from version-controlled fixtures; the data files above are the record of what was measured. Write-up drafted with AI assistance and checked against Luceria’s editorial standards.