File size: 7,675 Bytes
7759bfb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
"""
Deterministic verification for the LaTeX resume flow (src/latex_resume.py).

Proves, without any LLM or LaTeX engine:
  1. LaTeX → text extraction recovers the resume's words.
  2. Honestly-includable JD keywords (PM/AI/SaaS craft) get injected into the
     LaTeX and therefore appear in the extracted text.
  3. BLOCKED / fabrication-risk terms (certifications, seniority, employers,
     specialised engineering) are NEVER injected in ANY placement.
  4. External-style coverage rises sharply after injection.
  5. Keywords are DISTRIBUTED, not dumped: a Summary sentence, woven experience
     \\item clauses, and at most ONE compact competencies line — and re-running
     does not stack fragments (idempotent).

Run:  python scripts/verify_latex_resume.py
"""
import os
import re
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from src.latex_resume import (
    latex_to_text, inject_keywords, optimize_latex_resume,
    _INJECT_MARKER, _INJECT_END, _INJECT_WEAVE,
)
from src.external_ats import extract_external_keywords, external_coverage


SAMPLE_LATEX = r"""
\documentclass[11pt]{article}
\usepackage[margin=0.75in]{geometry}
\begin{document}
\textbf{Jane Doe} \\
Product Manager

\section*{Summary}
Product manager who ships data-informed features and works with engineering and
design to deliver customer value. Owned the product roadmap for a consumer app.

\section*{Experience}
\textbf{Product Manager, Acme} \\
\begin{itemize}
  \item Led discovery and defined the product backlog for a B2B dashboard.
  \item Ran A/B tests and shipped onboarding improvements that lifted activation.
\end{itemize}

\section*{Education}
B.Tech, Computer Science
\end{document}
"""

# A JD full of normal PM/Product/AI/SaaS vocabulary + a few fabrication-risk terms.
SAMPLE_JD = """
We are hiring a Senior AI Product Manager. You will own product strategy and the
product roadmap, drive stakeholder management, and partner with engineering on
machine learning and generative AI features. Strong skills in product analytics,
experimentation, A/B testing, go-to-market, user research, and agile delivery.
SaaS and B2B experience preferred. Must have a CISSP certification, a PMP, and
12+ years of experience. Hands-on Kubernetes and CUDA kernel programming required.
"""

# Terms we must NEVER fabricate even though they appear in the JD.
MUST_NOT_INJECT = ["cissp", "pmp", "12+ years", "cuda"]


def main() -> int:
    print("=" * 70)
    print("LaTeX resume flow verification")
    print("=" * 70)

    # 1. Text extraction recovers resume words.
    base_text = latex_to_text(SAMPLE_LATEX)
    low = base_text.lower()
    assert "product manager" in low, "extraction lost 'product manager'"
    assert "backlog" in low, "extraction lost 'backlog'"
    assert "\\section" not in base_text, "extraction left raw LaTeX commands"
    print(f"[1] LaTeX-to-text OK ({len(base_text)} chars, no raw commands)")

    # 2/3/4. Full optimize in Maximum ATS Mode (no compile — text path only).
    report = optimize_latex_resume(
        SAMPLE_LATEX, SAMPLE_JD,
        maximum_ats_mode=True,
        compile_pdf=False,
    )
    injected = [t.lower() for t in report["injected"]]
    expected = report["expected_terms"]
    before = external_coverage(expected, latex_to_text(SAMPLE_LATEX))
    after_pct = report["pct"]

    print(f"[2] expected terms: {len(expected)} | injected: {len(injected)}")
    print(f"    coverage before: {before['pct']}%  ->  after: {after_pct}%")

    # Some craft terms that should be safely injected (present in JD, low risk).
    want_some = [t for t in ("product strategy", "product roadmap",
                             "stakeholder management", "generative ai",
                             "machine learning", "a/b testing", "go-to-market",
                             "user research", "saas", "b2b")
                 if t in [e.lower() for e in expected]]
    injected_or_present = set(injected) | {p.lower() for p in report["present"]}
    covered_craft = [t for t in want_some if t in injected_or_present]
    assert len(covered_craft) >= 5, (
        f"expected >=5 craft terms covered, got {covered_craft}")
    print(f"[3] craft terms covered ({len(covered_craft)}): {covered_craft}")

    # 3. No fabrication-risk term was injected in ANY placement (summary
    #    sentence, woven \item clauses, or the competencies line).
    tex = report["tex"]
    frags = _injected_fragments(tex)
    bad = [t for t in MUST_NOT_INJECT if t in injected or t in frags]
    assert not bad, f"FABRICATION: injected blocked terms {bad}"
    print(f"[4] no fabrication: blocked terms absent from EVERY injected "
          f"placement ({MUST_NOT_INJECT})")

    # 4. Coverage improved meaningfully.
    assert after_pct >= before["pct"], "coverage did not improve"
    assert after_pct >= 70, f"coverage only {after_pct}% (expected >=70%)"
    print(f"[5] coverage improved {before['pct']}% -> {after_pct}% (>=70 target)")

    # 5. Distribution: at most one competencies line, a Summary sentence, and
    #    woven experience / multi-section placement (no single dump block).
    comp_lines = tex.count(r"\textbf{Core Competencies:}")
    assert comp_lines <= 1, f"expected <=1 competencies line, got {comp_lines}"

    assert "Core focus areas include" in tex, (
        "no Summary placement sentence (SAMPLE_LATEX has \\section*{Summary})")

    woven = ("(applying" in tex) and (_INJECT_WEAVE in tex)
    added_sections = {k["section"] for k in report["keywords"]
                      if k["found_in_export"] and k["section"].endswith("(added)")}
    multi_section = any(s in ("Summary (added)", "Experience (added)")
                        for s in added_sections)
    assert woven or multi_section, (
        f"no distributed placement detected (sections={sorted(added_sections)})")
    print(f"[6] distribution OK: {comp_lines} competencies line, Summary sentence "
          f"present, woven={woven}, sections={sorted(added_sections)}")

    # 6. Structure + idempotency: balanced document, and re-running injection
    #    reproduces the same fragments rather than stacking them.
    assert tex.count(r"\end{document}") == 1, "broken document env"
    again, _ = inject_keywords(tex, report["injected"])
    assert again.count("Core focus areas include") == \
        tex.count("Core focus areas include"), "summary not idempotent"
    assert again.count(r"\textbf{Core Competencies:}") == comp_lines, \
        "competencies line not idempotent"
    assert again.count(_INJECT_WEAVE) == tex.count(_INJECT_WEAVE), \
        "woven clauses not idempotent"
    assert again.count(_INJECT_MARKER) == tex.count(_INJECT_MARKER), \
        "marker fragments not idempotent"
    print("[7] structure OK: balanced document, fragments stable on re-run "
          "(idempotent)")

    print("=" * 70)
    print("PASS — LaTeX flow DISTRIBUTES honest keywords (summary + experience +")
    print(f"       one competencies line), blocks fabrication, coverage {after_pct}%.")
    print("=" * 70)
    return 0


def _injected_fragments(tex: str) -> str:
    """Concatenate the lowercased text of every injected fragment: the fenced
    blocks (summary sentence + competencies line) AND inline woven clauses."""
    low = tex.lower()
    parts = []
    block_pat = re.escape(_INJECT_MARKER.lower()) + r".*?" + \
        re.escape(_INJECT_END.lower())
    parts += re.findall(block_pat, low, flags=re.DOTALL)
    weave_pat = r" \(applying [^\n]*?\)" + re.escape(_INJECT_WEAVE.lower())
    parts += re.findall(weave_pat, low)
    return " ".join(parts)


if __name__ == "__main__":
    sys.exit(main())