Description text that did not originate from a glyph bullet (•) is present in the parse and on the reconstructed résumé, but absent from the downloaded PDF. The user sees a line on screen, downloads, and it is gone.
Found while implementing #492 (PR #842); pre-existing, not caused by that work.
Mechanism
resolveBullets in src/lib/pdf/ats-resume-model.ts prefers the graded BulletObservation pool. src/lib/heuristics/group-bullets.ts documents that pool as "extracted from rawText" — i.e. glyph bullets only. Any description entry that reached the field by another route has no BulletObservation backing it and is dropped at render.
There are at least two such routes today, both legitimate:
Concretely, on tests/fixtures/pdfs/unknown/headerless-experience.pdf, role 1's "Leads the automation guild." is on description in the parse and renders on the reconstructed résumé, but does not appear in the exported PDF.
Why no gate caught it
The round-trip invariant (corpus-roundtrip.test.ts) compares only title / company / start_date / end_date. description is outside the compared set, so parse → export → re-parse stays green while the content silently disappears. Nothing regressed; the gap was simply never observable.
Acceptance criteria
Notes
Worth checking whether this is the same root as any open export-fidelity issue before building — the parse-model ↔ export-model seam has come up before, and the fix belongs wherever that seam is owned rather than patched at the call site.
Refs #811
Description text that did not originate from a glyph bullet (
•) is present in the parse and on the reconstructed résumé, but absent from the downloaded PDF. The user sees a line on screen, downloads, and it is gone.Found while implementing #492 (PR #842); pre-existing, not caused by that work.
Mechanism
resolveBulletsinsrc/lib/pdf/ats-resume-model.tsprefers the gradedBulletObservationpool.src/lib/heuristics/group-bullets.tsdocuments that pool as "extracted from rawText" — i.e. glyph bullets only. Anydescriptionentry that reached the field by another route has noBulletObservationbacking it and is dropped at render.There are at least two such routes today, both legitimate:
belowAnchorBodyProse→description, the path [parser] experience — unbulleted line between the date sub-line and the bullets is silently dropped #615 and [parser] experience — a below-anchor scope line with no;, no grade-code middot and no terminal punctuation still fills an emptyteam#708 established for below-anchor scope lines.splitAnchorProseTail(entry-blocks.ts, added in Parser drops entire work history when the experience section has no header #492).Concretely, on
tests/fixtures/pdfs/unknown/headerless-experience.pdf, role 1's"Leads the automation guild."is ondescriptionin the parse and renders on the reconstructed résumé, but does not appear in the exported PDF.Why no gate caught it
The round-trip invariant (
corpus-roundtrip.test.ts) compares onlytitle/company/start_date/end_date.descriptionis outside the compared set, so parse → export → re-parse stays green while the content silently disappears. Nothing regressed; the gap was simply never observable.Acceptance criteria
descriptioncontent survives export to the downloaded PDF.headerless-experience.pdfalready reproduces and needs no new binary.descriptionshould join the round-trip comparison set. If not, say why in the test's docblock, so the next person doesn't read the green gate as coverage.preemptedIsHeadertoken-coverage filter inresolveDescriptionexists to prevent exactly that on the parse side).Notes
Worth checking whether this is the same root as any open export-fidelity issue before building — the parse-model ↔ export-model seam has come up before, and the fix belongs wherever that seam is owned rather than patched at the call site.
Refs #811