#4261·career-ops

verify-ats.mjs under-scores every non-English CV: HTML entities undecoded and English-only heading patterns

Author: wail-archCreated Sep 17, 2026Updated Sep 17, 2026

Summary

verify-ats.mjs under-scores every non-English CV, by enough to fail the gate. The same CV content scored 99/100 (A) in English and 82/100 (B) in French. The CV was not the problem.

Two independent causes.

1. HTML entities are never decoded

stripInline() strips tags but leaves entities:

function stripInline(fragment) {
  return collapse(fragment.replace(/<[^>]+>/g, ' '));
}

A generated CV contains Exp&eacute;rience professionnelle. That reaches the matcher as exp eacute rience professionnelle and matches nothing.

asciiFold('Expérience professionnelle')      -> "experience professionnelle"   // matches
asciiFold('Exp&eacute;rience professionnelle') -> "exp eacute rience professionnelle" // does not

2. Section-heading patterns are English-only, and lib/ascii-fold.mjs is not used

{ name: 'Experience', re: /experience|work history|employment/ },
{ name: 'Education',  re: /education|academic/ },
{ name: 'Skills',     re: /skills|competenc|proficienc/ },

Formation never matches education. Compétences would match competenc once folded, but nothing folds it.

This is the third instance of the bug lib/ascii-fold.mjs already documents in its own docstring, which names verify-portals.mjs and providers/_trust-validator.mjs. verify-ats.mjs is a third.

Impact

sections carries 20 of the 100 points. A French, German, Arabic, Japanese or Turkish CV loses 15 of them plus most of the bonus, so a structurally perfect CV scores in the low 80s. Since career-ops ships modes for fr, de, ar, ja and tr, every user of those modes is affected. The failure is silent: it reads as a defect in the user's CV, and the obvious "fix" is to anglicise the headings of a French CV, which is the wrong outcome.

Reproduce

node build-cv-onepage.mjs        # or any pdf-mode build
node verify-ats.mjs output/<cv>-en.html   # 99/100
node build-cv-onepage.mjs fr
node verify-ats.mjs output/<cv>-fr.html   # 82/100, critical: missing Experience, Education, Skills

Fix (tested locally, both languages now 99/100, English unchanged)

  1. Decode entities inside stripInline() before collapsing (numeric, hex, and the Latin-1 named set).
  2. asciiFold() each heading in extractHeadings() before matching, since the patterns are ASCII by construction.
  3. Extend the required and bonus patterns to the languages the repo ships modes for: formation, diplome, kenntnisse, beceri, 職歴, المهارات, and so on.

node test-all.mjs shows no regressions from this change (same pre-existing failures before and after).

Happy to open a PR if you want it in this shape.