Skip to content

Shared lexicon (a): one bullet-glyph vocabulary — ⁃ and — are parser bullets the scorer silently drops #915

Description

@s-annam

Part (a) of #653. Not a good first issue — this one changes scoring behaviour and needs per-glyph human adjudication.

Problem

The bullet-glyph vocabulary exists as divergent copies, and the divergence is live: glyphs the parser treats as bullets are invisible to the scorer, so those bullets drop out of the Specificity pool.

Verified divergence:

site class
src/lib/heuristics/line-primitives.ts:35 (BULLET_CLASS) [•‣▪●◦⁃*\-–—]
src/lib/heuristics/sections.ts:145 (VISUAL_BULLET_RE) [•‣▪●◦⁃*\-–—]
src/lib/heuristics/regex.ts:321 (LEADING_BULLET_RE) [•‣▪●◦⁃*\-–—]
src/lib/score/score.ts:136 (BULLET_MARKER_RE) [-*•●–▪◦‣▶►·�]
src/lib/score/score.ts:789 (LONE_BULLET_RE) [•●▪◦‣▶►·�]
src/lib/edit/apply-overrides.ts:105 (LEADING_MARKER_RE) [-*•●–▪◦‣▶►·�]

Plus copies in markdown-emit.ts, extract/group-bullets.ts and webllm/localize/achievements.ts — 8 in total per the #646 review.

(U+2043 hyphen bullet) and (em dash) are parser bullets absent from the scorer's class. A résumé using either has its Experience bullets segmented correctly by the parser and then silently skipped by extractBulletsFromLines (score.ts:808-822), deflating Specificity. Conversely , , · and are scorer-only.

Why this is separate from #653(b)/(c)/(d)

Merging the sets changes scores on existing résumés. That is a deliberate behaviour change requiring a version bump and a reviewed rebaseline, which is why it cannot ride along with the behaviour-preserving consolidations.

Implementation plan

  1. Mint a new import-nothing leaf for the glyph vocabulary. House precedent is extract/title-shape.ts. Not line-primitives.ts — it imports regex.ts, and deriving there re-creates the cycle regex.ts:317-321 exists to avoid, dragging the 672-line regex.ts and its module-eval Intl gazetteer onto the eager entry graph via the score/edit consumers (the feat: primary role targeting, editable headline, and job-search handoff (#598) #605 failure class).
  2. Adjudicate each glyph explicitly: for every symbol in the union, decide parser-bullet / scorer-bullet / both, and write the reason down. - and in particular are ambiguous (a leading hyphen is also a date-range fragment and a negated number — see cleanRewriteLine eats the minus sign off a line-initial negative number (-5% churn5% churn) #821).
  3. Derive all 8 copies from the leaf as named exported sets, preserving any distinction that survives adjudication as its own derived constant rather than collapsing it.
  4. Bump ATS_SCORE_ALGO_VERSION.
  5. Rebaseline the 54 corpus snapshots; review the score deltas fixture by fixture.

Acceptance criteria

  • One import-nothing leaf owns the glyph vocabulary; all 8 sites derive from it.
  • The leaf imports nothing, asserted by a test (follow title-shape.ts's contract).
  • Per-glyph adjudication is written down in the leaf's docblock, not just in the PR.
  • ATS_SCORE_ALGO_VERSION bumped.
  • Corpus rebaseline reviewed fixture-by-fixture; score deltas explained in the PR description.
  • A regression test covers a -bulleted and an -bulleted résumé reaching the Specificity pool.
  • The / entry chunk does not gain regex.ts (build-verified).

Parent: #653. Roadmap item 5(a) of #646.

Metadata

Metadata

Assignees

No one assigned

    Labels

    improvementEnhancing existing functionalityrefactorCode restructuring without behavior change

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions