Problem
Editing a role's or project's prose description on / changes the exported résumé but
does not re-grade the score. The edit folds into editedCore, but the score memo in
src/hooks/useAnalyzedResume.ts does not list descriptionOverrides as a dependency, so
it never re-runs for that channel.
descriptionOverrides writes experience[].description, and src/lib/score/score.ts
(computeAnonymousAtsScore) uses exactly that field as the bullet-pool fallback for
glyph-less résumés:
if (extractExperienceSectionBullets(input.sections).length === 0) {
bullets.push(...poolExperienceDescriptions(input.parsed.experience));
}
So on a Word / Google-Docs-Skia style résumé whose Experience section yields no marker
bullets, the description is the graded pool — and editing it silently grades the
pre-edit text.
Repro
- Load a glyph-less-prose résumé on
/ (an Experience section with no • markers).
- Edit a role description through the reconstructed résumé.
- Observe the score object is identical — overall stays at its pre-edit value.
- Touch any other scoring channel (a skill, the summary, a contact field) — the score
jumps to the value the description edit should already have produced.
Two further symptoms of the same stale pool:
score.bullets keeps the pre-edit bullet text.
groupBulletsByExperience over that stale pool returns experienceIndex: null, so the
role's editable rows detach into the "Other" bucket in the UI.
Export is unaffected — applyOverrides folds the edit correctly; only the grade is stale.
Where
src/hooks/useAnalyzedResume.ts — the score useMemo (line 258 on main). Its dep
array names contactOverrides, experienceOverrides, bulletOverrides,
educationOverrides, achievementOverrides, certificationOverrides, skillsOverride,
summaryOverride, addedEntries, addedBullets, removedBullets, removedEntries,
claimedBulletKeys and the four scoreAffectingProfileSlots primitives —
descriptionOverrides is absent.
profileOverrides is also absent, but that one is deliberate and documented (#428: it is
stood in for by scoreAffectingProfileSlots so a non-scoring link edit keeps the score
object reference identical). descriptionOverrides has no such justification.
Why it matters now
Pre-existing and long-standing, but less detectable since #652 (PR #922). The score
dep list and the fold memo's dep list used to sit adjacent and spell out the same fourteen
override maps, so an omission was visible by diffing the two arrays. The fold memo is now
[base, doneScoreBullets, snapshot], so a new override channel joins the fold
automatically and joins the score only by hand. #922 added a comment naming the knowingly
absent channels to restore some of that signal, but the defect itself is untouched.
Proposed fix
Add descriptionOverrides to the score memo's dep array, and add a regression test
alongside the existing useAnalyzedResume score-reference-stability tests asserting that a
description edit on a glyph-less-prose parse mints a new score object with a changed
overall.
Consider also whether the hand-maintained dep list is the right mechanism at all: a
derived "score-affecting slice of the snapshot" — the shape scoreAffectingProfileSlots
already uses for profileOverrides — would make the omission structural rather than
clerical. That is a larger change and can be a follow-up.
Acceptance criteria
Found during the PR review of #922 (which documents it as out of scope, correctly).
Problem
Editing a role's or project's prose description on
/changes the exported résumé butdoes not re-grade the score. The edit folds into
editedCore, but thescorememo insrc/hooks/useAnalyzedResume.tsdoes not listdescriptionOverridesas a dependency, soit never re-runs for that channel.
descriptionOverrideswritesexperience[].description, andsrc/lib/score/score.ts(
computeAnonymousAtsScore) uses exactly that field as the bullet-pool fallback forglyph-less résumés:
So on a Word / Google-Docs-Skia style résumé whose Experience section yields no marker
bullets, the description is the graded pool — and editing it silently grades the
pre-edit text.
Repro
/(an Experience section with no•markers).jumps to the value the description edit should already have produced.
Two further symptoms of the same stale pool:
score.bulletskeeps the pre-edit bullet text.groupBulletsByExperienceover that stale pool returnsexperienceIndex: null, so therole's editable rows detach into the "Other" bucket in the UI.
Export is unaffected —
applyOverridesfolds the edit correctly; only the grade is stale.Where
src/hooks/useAnalyzedResume.ts— thescoreuseMemo(line 258 onmain). Its deparray names
contactOverrides,experienceOverrides,bulletOverrides,educationOverrides,achievementOverrides,certificationOverrides,skillsOverride,summaryOverride,addedEntries,addedBullets,removedBullets,removedEntries,claimedBulletKeysand the fourscoreAffectingProfileSlotsprimitives —descriptionOverridesis absent.profileOverridesis also absent, but that one is deliberate and documented (#428: it isstood in for by
scoreAffectingProfileSlotsso a non-scoring link edit keeps the scoreobject reference identical).
descriptionOverrideshas no such justification.Why it matters now
Pre-existing and long-standing, but less detectable since #652 (PR #922). The
scoredep list and the fold memo's dep list used to sit adjacent and spell out the same fourteen
override maps, so an omission was visible by diffing the two arrays. The fold memo is now
[base, doneScoreBullets, snapshot], so a new override channel joins the foldautomatically and joins the score only by hand. #922 added a comment naming the knowingly
absent channels to restore some of that signal, but the defect itself is untouched.
Proposed fix
Add
descriptionOverridesto thescorememo's dep array, and add a regression testalongside the existing
useAnalyzedResumescore-reference-stability tests asserting that adescription edit on a glyph-less-prose parse mints a new score object with a changed
overall.
Consider also whether the hand-maintained dep list is the right mechanism at all: a
derived "score-affecting slice of the snapshot" — the shape
scoreAffectingProfileSlotsalready uses for
profileOverrides— would make the omission structural rather thanclerical. That is a larger change and can be a follow-up.
Acceptance criteria
overall,
score.bulletscarries the edited text.groupBulletsByExperienceattributes the edited role's bullets back to their role(no
experienceIndex: nulldetachment into "Other").reference identical.
mainbefore the fix.npm run verifygreen.Found during the PR review of #922 (which documents it as out of scope, correctly).