Three root causes fixed:
- _section_text_for_prompt: strip existing bullet chars from bullet text before
adding the prompt's own marker (prevents • • text entering the LLM prompt)
- _reparse_experience_bullets: use + quantifier to strip all leading bullet chars,
not just the first (handles • • text from LLM output)
- _apply_section_rewrite (summary): run _clean_summary_markup to remove
markdown * bullets from career_summary before storing in struct
Also adds 'no markdown formatting' to the LLM rewrite prompt CRITICAL RULES.
Summary and experience bullet fields in the review modal are now
editable textareas. Edited values flow through decisions to
apply_review_decisions(), which uses edited_text/edited_bullets when
the section is accepted. Clearing unwanted LLM-added bullets (empty
lines filtered server-side) addresses the extra-bullets issue.
The preview textarea in the apply workspace is also now editable;
approveResume() passes preview_text_override so manual edits survive
the approve step without re-rendering from struct.
- Add _try_rerank() to job_ranker.py: after stack_score sort, rerank
top-50 candidates by (resume_text, description) cross-encoder relevance
- Add resume_text param to rank_jobs(); graceful no-op when empty
- Add reranker gap-reordering pass in rewrite_for_ats(): gaps sorted by
(jd_text, term) relevance before section grouping and LLM rewrite
- Both integrations fall back silently on ImportError or inference failure
- 13 new tests; CF_RERANKER_MOCK=1 for zero-weight test runs
- Closes#108
LLMs occasionally emit backslash sequences that are valid regex but not valid
JSON (e.g. \s, \d, \p). This caused extract_jd_signals() to fall through to
the exception handler, leaving llm_signals empty. With no LLM signals, the
optimizer fell back to TF-IDF only — which is more conservative and can
legitimately return zero gaps, making the UI appear to say the resume is fine.
Fix: strip bare backslashes not followed by a recognised JSON escape character
(" \ / b f n r t u) before parsing. Preserves \n, \", etc.
Reproduces: cover letter generation concurrent with gap analysis raises the
probability of a slightly malformed LLM response due to model load.