#!/usr/bin/env python3 """Deterministic regression for Phase 08-02: Non-destructive tailoring (R17). It MUST be impossible for this script to pass while the candidate's real history can be altered. It proves: 1. STATIC: every bullet-mutation call site in resume_customizer.py (_weave_keywords_into_bullets / _force_weave_into_bullets) is gated by `non_destructive`, and _maximize_external_coverage takes a non_destructive parameter. (Adding a new unguarded mutation site fails this.) 2. END-TO-END: _generate_resume_v4 run with a destructive no-LLM stub provider and _maximum_ats_mode=True yields a DOCX whose role titles, companies, dates, and EXISTING bullets are byte-identical to the base resume, the destructive LLM output is discarded, and no fabrication term appears. 3. UNIT: _apply_non_destructive preserves roles verbatim, appends <=3 bullets per role, and never appends a fabrication-risk term (cissp/pmp/cuda). 4. LATEX: inject_keywords appends new \\item lines (no in-place edits), keeps one competencies line + a summary sentence, and is idempotent. No real LLM, no LaTeX engine, no network. ASCII-only output. Exit 0 on success. """ import os import re import sys import tempfile REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if REPO_ROOT not in sys.path: sys.path.insert(0, REPO_ROOT) CUST_PATH = os.path.join(REPO_ROOT, "src", "resume_customizer.py") _failures = [] def check(condition, message): if condition: print(f" [PASS] {message}") else: print(f" [FAIL] {message}") _failures.append(message) # ── 1. STATIC call-site guard check ───────────────────────────────────────── def test_static_guards(): print("[1] Static: all bullet-mutation call sites gated by non_destructive") src = open(CUST_PATH, encoding="utf-8").read() check("NON_DESTRUCTIVE_DEFAULT" in src and "_apply_non_destructive" in src and "_append_keyword_bullets" in src, "non-destructive mode + append helpers present") check(bool(re.search(r"def _maximize_external_coverage\([^)]*non_destructive", src, re.S)), "_maximize_external_coverage takes a non_destructive parameter") calls = [m.start() for c in ("_weave_keywords_into_bullets(", "_force_weave_into_bullets(") for m in re.finditer(re.escape(c), src)] unguarded = [i for i in calls if "non_destructive" not in src[max(0, i - 400):i]] check(not unguarded, f"every weave/force-weave occurrence ({len(calls)}) is non_destructive-guarded") # ── 2. END-TO-END diff through the live max-ATS path ──────────────────────── def _build_base_resume(): from src.resume_model import Resume, Role, Contact, Education return Resume( name="Jordan Tester", contact=Contact(email="jordan@example.com", phone="555-0100", location="Hyderabad, Telangana, India"), summary="Product manager with delivery experience across teams.", skills=[], roles=[ Role(title="Senior Product Manager", company="Acme Qwerty Labs", location="Remote", dates="Jan 2021 - Present", bullets=[ "Spearheaded zylotron onboarding revamp lifting activation by forty percent.", "Owned blorptastic pricing experiments across enterprise cohorts.", "Led quibblefax vendor integration from scoping to launch.", ]), Role(title="Associate Product Owner", company="Bumblewick Systems", location="Pune", dates="Jun 2018 - Dec 2020", bullets=[ "Drove frobnicator dashboard adoption to scale across regions.", "Managed wuggle backlog and release cadence for two squads.", "Shipped znorf analytics module improving retention.", ]), ], education=[Education(degree="MBA", institution="Northwind Institute", dates="2017")], ) class _StubProvider: """No-LLM provider that RETURNS DESTRUCTIVE output (renamed titles + rewritten bullets) to prove the pipeline discards it in non-destructive mode.""" name = "stub" def __init__(self, destructive_dict): self._d = destructive_dict def tailor_resume(self, base_dict, jd, title, company, raw): return self._d, "ok" def test_end_to_end(): print("[2] End-to-end: _generate_resume_v4 (_maximum_ats_mode=True) preserves history") from src.resume_customizer import ResumeCustomizer, _read_docx_text base = _build_base_resume() dd = base.to_dict() dd["summary"] = "REWRITTENSUMMARY tailored pitch." for i, r in enumerate(dd["roles"]): r["title"] = f"RENAMEDTITLE{i} Chief Officer" r["bullets"] = [f"REWRITTENBULLET{i}A delivered value", f"REWRITTENBULLET{i}B drove growth"] stub = _StubProvider(dd) jd = ("We need product roadmap ownership, stakeholder management, and a/b " "testing experience for a SaaS B2B product. Strong user research and " "go-to-market skills required.") tmp = tempfile.mkdtemp(prefix="nd_e2e_") try: cust = ResumeCustomizer(None, base.to_flat_text(), tmp) fp = os.path.join(cust.output_dir, "out.docx") job = { "title": "Product Manager", "company": "Northwind", "description": jd, "ats_keywords": "", "_raw_assessment": {}, "_maximum_ats_mode": True, "_confirmed_terms": [], } path = cust._generate_resume_v4(job, cfg=None, filepath=fp, provider=stub, base_resume_override=base) check(bool(path) and os.path.exists(path), "generation returned a DOCX path") if not path or not os.path.exists(path): return text = _read_docx_text(path) low = text.lower() # Titles / companies / dates verbatim. for token in ("Senior Product Manager", "Associate Product Owner", "Acme Qwerty Labs", "Bumblewick Systems"): check(token in text, f"verbatim preserved: '{token}'") check("2021" in text and "2018" in text, "employment dates preserved") # Existing bullets verbatim (distinctive tokens). for token in ("zylotron", "blorptastic", "quibblefax", "frobnicator", "wuggle", "znorf"): check(token in low, f"existing bullet token preserved: '{token}'") # Destructive ROLE output discarded (renamed titles + rewritten bullets). # NOTE: R17 PERMITS summary augmentation, so the tailored summary may # legitimately differ — only role content must be preserved verbatim. for bad in ("renamedtitle", "rewrittenbullet"): check(bad not in low, f"destructive role output discarded: '{bad}'") # No fabrication anywhere. for fab in ("cissp", "pmp", "cuda", "12+ years"): check(fab not in low, f"no fabrication term in export: '{fab}'") finally: import shutil shutil.rmtree(tmp, ignore_errors=True) # ── 3. UNIT: _apply_non_destructive ───────────────────────────────────────── def test_apply_non_destructive_unit(): print("[3] Unit: _apply_non_destructive preserves roles + caps appended bullets") from src.resume_customizer import ResumeCustomizer from src.resume_model import Resume base = _build_base_resume() # A 'destructive' tailored copy with renamed titles + rewritten bullets. dd = base.to_dict() for i, r in enumerate(dd["roles"]): r["title"] = f"FAKE{i}" r["bullets"] = [f"FAKEBULLET{i}"] tailored = Resume.from_dict(dd) tmp = tempfile.mkdtemp(prefix="nd_unit_") try: cust = ResumeCustomizer(None, base.to_flat_text(), tmp) cust._apply_non_destructive( tailored, base, include_terms=["product roadmap", "stakeholder management", "a/b testing", "cissp", "pmp", "cuda"], jd_text="product roadmap stakeholder management a/b testing", ) for ti, role in enumerate(tailored.roles): bro = base.roles[ti] check(role.title == bro.title and role.company == bro.company and role.dates == bro.dates, f"role {ti}: title/company/dates verbatim") check(role.bullets[:len(bro.bullets)] == list(bro.bullets), f"role {ti}: existing bullets verbatim") extra = len(role.bullets) - len(bro.bullets) check(0 <= extra <= 3, f"role {ti}: <=3 bullets appended ({extra})") appended = " ".join(role.bullets[len(bro.bullets):]).lower() for fab in ("cissp", "pmp", "cuda"): check(fab not in appended, f"role {ti}: no fabrication term appended ('{fab}')") finally: import shutil shutil.rmtree(tmp, ignore_errors=True) # ── 4. LATEX preservation ─────────────────────────────────────────────────── SAMPLE_LATEX = ( "\\documentclass{article}\n\\begin{document}\n" "\\section*{Summary}\nExperienced PM.\n" "\\section*{Experience}\n\\begin{itemize}\n" "\\item Led onboarding discovery research.\n" "\\item Shipped the v1 analytics module.\n" "\\end{itemize}\n\\end{document}\n" ) def test_latex_preservation(): print("[4] LaTeX: inject_keywords appends items, no in-place edits, idempotent") from src.latex_resume import inject_keywords terms = ["product strategy", "stakeholder management", "a/b testing", "user research"] out, inj = inject_keywords(SAMPLE_LATEX, terms) check("Led onboarding discovery research." in out and "Shipped the v1 analytics module." in out, "existing \\item lines unchanged") check("(applying" not in out, "no in-place '(applying X)' edits") n = out.count("% ats-item") check(1 <= n <= 3, f"1..3 appended \\item lines ({n})") check(out.count("\\textbf{Core Competencies:}") <= 1, "at most one competencies line") check("core focus areas include" in out.lower(), "summary sentence present") out2, _ = inject_keywords(out, terms) check(out2.count("% ats-item") == n, "idempotent (re-run does not stack items)") def main(): print("=" * 70) print("Phase 08-02 verification: Non-destructive tailoring (R17)") print("=" * 70) test_static_guards() test_end_to_end() test_apply_non_destructive_unit() test_latex_preservation() print("-" * 70) if _failures: print(f"FAIL - {len(_failures)} check(s) failed:") for f in _failures: print(f" - {f}") return 1 print("PASS - tailoring is non-destructive end-to-end (history preserved, " "keywords appended, honesty intact)") return 0 if __name__ == "__main__": sys.exit(main())