JAA-ATS-Tool / scripts /verify_non_destructive.py
saitejatirunagari's picture
feat: non-destructive tailoring + reliable PDF + persistent side panel + history (Phase 8)
8155d78
Raw
History Blame
11.4 kB
#!/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())