File size: 3,877 Bytes
f5dd879
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Deterministic regression for External ATS Feedback Repair Mode.

Uses StubProvider (no API keys). Pastes fake external-checker feedback that mixes:
  - LOW/plausible PM terms (should be woven in),
  - a BLOCKED credential (CISSP — must NEVER appear),
  - a HIGH-risk specialized term (SIEM — must NOT be auto-added; surfaced for
    confirmation).

Asserts the honesty guarantees hold: blocked/high terms stay OUT of the resume,
scores come from the re-parsed export, and the result carries the right buckets.
"""
import os, sys, io, shutil
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
sys.path.insert(0, os.path.abspath("."))

# Isolate the vault so prior confirmations don't change results.
import src.candidate_vault as _cv
_cv._VAULT_PATH = "data/_test_vault_feedback.json"
if os.path.exists(_cv._VAULT_PATH):
    os.remove(_cv._VAULT_PATH)

import shutil as _sh
src_pdf = r"C:\Users\Nxtwave\Desktop\resume\Saiteja_Tirunagari_Resume A 26 - Copy.pdf"
dst = "data/resume/resume.pdf"
os.makedirs("data/resume", exist_ok=True)
if not os.path.exists(dst) and os.path.exists(src_pdf):
    _sh.copyfile(src_pdf, dst)

from src.resume_parser_v2 import parse_resume_pdf
from src.providers import StubProvider
from src.jobalytics_repair import parse_external_feedback, repair_with_external_feedback
from src.resume_customizer import _read_docx_text

ok = True
def check(name, cond, detail=""):
    global ok; ok = ok and cond
    print(f"  [{'PASS' if cond else 'FAIL'}] {name}  {detail}")

# 1. Feedback parser
fb = ("Resume Match 73%. Missing keywords: roadmap, stakeholder management, "
      "A/B testing, CISSP, SIEM. Matched keywords: agile, jira")
parsed = parse_external_feedback(fb)
print("1. parse_external_feedback:")
check("external_score parsed = 73", parsed["external_score"] == 73, str(parsed["external_score"]))
check("missing keywords parsed", "roadmap" in [m.lower() for m in parsed["missing_keywords"]]
      and "cissp" in [m.lower() for m in parsed["missing_keywords"]])
check("no trailing punctuation", all(not m.endswith(".") for m in parsed["missing_keywords"]))

# 2. Repair honesty
base = parse_resume_pdf(dst)
jd = open("tests/fixtures/jds/generic_pm_3_7yrs.txt", encoding="utf-8").read()
job = {"title": "Product Manager", "company": "TestCo", "description": jd, "_raw_assessment": {}}
res = repair_with_external_feedback(job, feedback_text=fb, provider=StubProvider(),
                                    base_resume=base, output_dir="data/output/resumes/_fb_test")
print("2. repair_with_external_feedback:", res.get("status"), res.get("scores"))
check("no error", "error" not in res, res.get("error", ""))
check("CISSP is blocked", "CISSP" in res.get("blocked_terms", []))
check("SIEM is unresolved-high", "SIEM" in res.get("unresolved_high_risk_terms", []))
check("external_score carried = 73", res.get("external_score") == 73)
check("scores present (internal/independent)",
      isinstance(res.get("scores", {}).get("internal_jd_match"), int)
      and isinstance(res.get("scores", {}).get("independent_jd_match"), int))

txt = _read_docx_text(res["resume_path"]).lower()
check("CISSP NOT in resume (no fabricated cert)", "cissp" not in txt)
check("SIEM NOT auto-added (high-risk, unconfirmed)", "siem" not in txt)

# 3. No-keywords guard
res2 = repair_with_external_feedback(job, feedback_text="great resume, no notes",
                                     provider=StubProvider(), base_resume=base,
                                     output_dir="data/output/resumes/_fb_test")
check("empty feedback -> no_missing_keywords error", res2.get("error") == "no_missing_keywords")

print("\n" + ("✓ ALL FEEDBACK-REPAIR CHECKS PASS" if ok else "✗ SOME FAILED"))
shutil.rmtree("data/output/resumes/_fb_test", ignore_errors=True)
if os.path.exists(_cv._VAULT_PATH):
    os.remove(_cv._VAULT_PATH)
sys.exit(0 if ok else 1)