Skip to content

Word resume template — name, phone, and skills mis-parsed (completeness 12/30) #29

Description

@sriyau64

Word resume template — name, phone, and skills mis-parsed (completeness 12/30)

Using a resume sample from a Microsoft Word "Office Manager" template, the phone number was visible in the extracted plain-text panel but did not appear in the score card. Deeper investigation shows the phone is one of three parsing failures on this document; overall completeness is 12/30.

Chanchal sharma sample.pdf (synthetic persona — PII-verified safe: body text, Info dict, XMP metadata, and fonts/ICC layers all checked clean)

Screenshot 1 — phone present in plain-text panel
Screenshot 2 — phone absent from score card

Summary

Running the full cascade on the attached PDF yields overall 12, completeness 12/30, with name, phone, and skills all reported as missing. The text layer is clean (ASCII + one en-dash; verified at codepoint level — no ToUnicode/CMap mojibake). The failures are entirely in the Tier-1 heuristic parser, which makes three layout assumptions that Word table/text-box templates break simultaneously.

Reproduction

  1. Open the attached PDF in ResumeLint.
  2. Observe completeness = 12/30.
  3. Score card shows name, phone, and skills missing (among others — see "Out of scope" below for the non-bugs).

Expected: name, phone, and skills all parsed and scored.

Root cause

Word's resume templates lay out the header name and skills section in tables/text-boxes. This produces three independent assumption-breaks in the single-pass heuristic parser:

  1. Name (src/lib/heuristics/extract-fields.ts:173) — The real name renders as two separate single-word lines (Chanchal / Sharma). extractName rejects any candidate with words.length < 2, so both name lines are individually disqualified. The two-word tagline "Office Manager" wins the slot at confidence 0.25 (below the anonymous contact floor of 0.5), and name is reported missing.

  2. Phone (src/lib/heuristics/phone.ts:187-200) — The phone number is (718) 555–0100 where the separator is an en-dash U+2013, not an ASCII hyphen. mightHavePhone() pre-gates on PHONE_RE whose separator class [\s.-]? excludes Unicode dashes, so PHONE_RE.test() returns false and findPhoneNumbersInText (PR feat(phone): locale-aware region derivation + fix two-column fixture phone #100, libphonenumber-js) is never invoked. findPhoneNumbersInText handles en-dashes natively — the fix is to make the pre-filter gate wide enough to let the call reach it, not to widen PHONE_RE itself.

  3. Skills (src/lib/heuristics/extract-fields.ts:469) — The skills are in a 3-column table. SKILL_SPLIT_RE = /[,;·•|/]+|\s{2,}/ splits correctly when pdfjs assembles a column row with 2+ spaces between entries. When a row is assembled with only a single space between columns, the entire row collapses to one token ("Organization Problem-solving Management"), which counts as 1 skill — below the minimum of 5 (extract-fields.ts:512) — so skills is reported missing.

Note: the text layer is not the problem. Fonts are subsetted Georgia + Calibri with a valid ToUnicode map; the raw text the cascade sees is byte-for-byte the visible text. ToUnicode/CMap mojibake is not the cause here.

Scope — what to fix

  • Name: reconstruct two-word name from adjacent single-word lines. When consecutive short lines at the top of the document together form a plausible full name (two words, title-cased), treat them as a single candidate before applying the words.length < 2 guard. (src/lib/heuristics/extract-fields.ts:165-205)

  • Phone: expand mightHavePhone's pre-filter to recognize Unicode dashes. In phone.ts:187-200, widen the pre-gate so that en-dash (U+2013), em-dash (U+2014), and figure dash (U+2012) allow the string through to findPhoneNumbersInText. PR feat(phone): locale-aware region derivation + fix two-column fixture phone #100 already wires findPhoneNumbersInText (which handles these chars natively) — the only missing piece is that mightHavePhone gates it out before it runs. Do not widen PHONE_RE itself — the fix is the pre-filter gate, not the regex matcher.

  • Skills: context-detect a single-space multi-token column run and split accordingly. When inside a recognized skills section, detect a run of tokens that are separated by single spaces and together form a plausible skills list, then split it. Do not widen SKILL_SPLIT_RE to \s+ unconditionally — that causes false-positive splits in ordinary prose. (src/lib/heuristics/extract-fields.ts:469)

Explicitly out of scope

  • Role dates showing as missing — The template uses placeholder text January 20XX / Sep 20XX. YEAR_RE = /\b(19|20)\d{2}\b/ correctly rejects 20XX. This is a fixture artifact (template placeholder), not a product bug. Do not modify YEAR_RE to accept 20XX as a valid year.

  • Summary missing — The template genuinely has no Summary, Objective, or Profile section. Not a detection failure.

  • LinkedIn missing — No LinkedIn URL appears in the document. Not a detection failure.

Acceptance criteria

  • parsed.name is the real name (not "Office Manager") for the Chanchal Word PDF.
  • parsed.phone is (718) 555-0100 (or equivalent normalized form) for the Chanchal Word PDF.
  • parsed.skills contains at least the skills visible in the template columns for the Chanchal Word PDF.
  • Completeness score rises above the 12/30 baseline for this document (role-dates, summary, and LinkedIn remain correctly absent — no strict numeric floor beyond the current baseline).
  • The committed Word fixture's expected snapshot is updated to reflect the corrected parsed output.

Test fixture

Commit the attached PDF to tests/fixtures/pdfs/word/chanchal-sharma-sample.pdf. The file has been verified PII-safe across all four layers (body text via pdftotext, Info dict via pdfinfo, XMP metadata, and fonts/ICC). After implementing fixes:

npm run bake-fixtures

Review and commit the updated expected snapshot. This fixture regression-guards all three fixes simultaneously.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions