Snapshot: full project state
This commit is contained in:
87
audit.py
Normal file
87
audit.py
Normal file
@@ -0,0 +1,87 @@
|
||||
# Procyon — self-audit before send. Every item must PASS before an application
|
||||
# is eligible for the user's approval/send gate.
|
||||
|
||||
import re
|
||||
|
||||
import db
|
||||
import tailor
|
||||
|
||||
|
||||
def run_audit(app_id, job, email_subject, email_body, tailored_resume):
|
||||
"""Run the checklist, log results, return list of {item, result, detail}."""
|
||||
checks = []
|
||||
|
||||
def add(item, result, detail):
|
||||
checks.append({'item': item, 'result': result, 'detail': detail})
|
||||
db.add_audit(app_id, job['id'], item, result, detail)
|
||||
|
||||
company = (job.get('company') or '').strip()
|
||||
title = (job.get('title') or '').strip()
|
||||
|
||||
# 1. Employer name present in email (personalization signal, NOT a safety gate — the LLM
|
||||
# often abbreviates ("PSI" for "Physical Superintelligence") or says "your team", and the
|
||||
# subject line already carries the company, so a missing exact match is only a WARN).
|
||||
if company:
|
||||
if company.lower() in (email_body or '').lower():
|
||||
add('Employer name in email', 'PASS', f'"{company}" appears in body')
|
||||
else:
|
||||
add('Employer name in email', 'WARN', f'"{company}" not verbatim in body (may be abbreviated)')
|
||||
else:
|
||||
add('Employer name in email', 'WARN', 'No company recorded — verify before send')
|
||||
|
||||
# 2. No leftover placeholder / other-company names
|
||||
placeholders = ['[company]', '[name]', '{{', '}}', 'lorem', 'TODO', 'xxx']
|
||||
found = [p for p in placeholders if p.lower() in (email_body or '').lower()]
|
||||
add('No placeholder tokens', 'FAIL' if found else 'PASS',
|
||||
f'placeholders: {found}' if found else 'clean')
|
||||
|
||||
# 3. Contact info present
|
||||
phone = db.get_setting('resume_phone', '')
|
||||
email = db.get_setting('resume_email', '')
|
||||
missing = []
|
||||
if phone and phone not in (email_body or ''):
|
||||
missing.append('phone')
|
||||
if email and email not in (email_body or ''):
|
||||
missing.append('email')
|
||||
add('Contact info in email', 'FAIL' if missing else 'PASS',
|
||||
f'missing: {missing}' if missing else 'phone + email present')
|
||||
|
||||
# 4. Subject present and sane length
|
||||
if not email_subject:
|
||||
add('Email subject', 'FAIL', 'missing')
|
||||
elif len(email_subject) > 120:
|
||||
add('Email subject', 'FAIL', f'too long ({len(email_subject)} chars)')
|
||||
else:
|
||||
add('Email subject', 'PASS', email_subject)
|
||||
|
||||
# 5. Tailored resume non-empty and no fabrication markers
|
||||
if not tailored_resume or len(tailored_resume) < 100:
|
||||
add('Tailored resume', 'FAIL', 'too short / empty')
|
||||
else:
|
||||
add('Tailored resume', 'PASS', f'{len(tailored_resume)} chars')
|
||||
|
||||
# 6. Resume is a real deterministic resume (was "targeting header matches job" — removed:
|
||||
# the resume is now deterministic and no longer carries a job-name header, so that check
|
||||
# always false-warned).
|
||||
if tailored_resume and len(tailored_resume) > 100:
|
||||
add('Resume present', 'PASS', f'{len(tailored_resume)} chars, deterministic facts')
|
||||
else:
|
||||
add('Resume present', 'FAIL', 'resume missing')
|
||||
|
||||
# 7. ATS keyword coverage — quality signal, never blocks sending (informational only).
|
||||
try:
|
||||
kws = tailor.extract_job_keywords(job.get('description') or '', top_n=12)
|
||||
cov, _kws, missing = tailor.ats_coverage(tailored_resume, kws)
|
||||
if cov >= 0.5:
|
||||
add('ATS keyword coverage', 'PASS', f'{int(cov*100)}% of top keywords present')
|
||||
else:
|
||||
add('ATS keyword coverage', 'WARN',
|
||||
f'{int(cov*100)}% — resume may not strongly echo this role ({", ".join(missing[:5])})')
|
||||
except Exception:
|
||||
add('ATS keyword coverage', 'WARN', 'could not compute')
|
||||
|
||||
return checks
|
||||
|
||||
|
||||
def all_pass(checks):
|
||||
return all(c['result'] != 'FAIL' for c in checks)
|
||||
Reference in New Issue
Block a user