You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
5.2 KiB
Python

"""Tests for the offline role-audit helpers (no network)."""
from datetime import date
from gimme_job.proactive import role_audit
def test_build_audit_prompt_lists_titles_once():
entries = [
{"title": "Dental Assistant", "role": "support"},
{"title": "Orthodontic Clinician I", "role": "unknown"},
{"title": "dental assistant", "role": "support"},
]
prompt = role_audit.build_audit_prompt(entries, max_titles=10)
assert "- [support] Dental Assistant" in prompt
assert "- [unknown] Orthodontic Clinician I" in prompt
assert prompt.count("Dental Assistant") == 1
def test_parse_audit_response_tolerates_prose():
text = (
"Here you go:\n"
'{"items":[{"title":"X","role":"target"}],'
'"proposals":[{"role":"support","term":" Front Desk ","reason":"r"},'
'{"role":"bogus","term":"x","reason":""}]}\n'
"Thanks"
)
parsed = role_audit.parse_audit_response(text)
assert parsed["items"][0]["role"] == "target"
assert parsed["proposals"] == [
{"role": "support", "term": "front desk", "reason": "r"}
]
def test_parse_audit_response_garbage():
parsed = role_audit.parse_audit_response("not json")
assert parsed["proposals"] == []
assert parsed["items"] == []
assert parsed["raw"] == "not json"
def test_append_auto_terms_dedupes(tmp_path):
from gimme_job.utils.json_io import read_yaml
path = tmp_path / "role_terms.auto.yaml"
proposals = [
{"role": "support", "term": "surgical tech", "reason": "r"},
{"role": "support", "term": "surgical tech", "reason": "r"},
{"role": "non_clinical", "term": "revenue cycle", "reason": ""},
{"role": "target", "term": "dentist", "reason": "already a code default"},
{"role": "non_clinical", "term": "the", "reason": "generic stopword"},
]
_, added = role_audit.append_auto_terms(proposals, path=path)
assert added == 2 # duplicate + code-default + stopword terms skipped
_, added2 = role_audit.append_auto_terms(proposals, path=path)
assert added2 == 0
data = read_yaml(path)
assert data["role_terms"]["support"] == ["surgical tech"]
assert data["role_terms"]["non_clinical"] == ["revenue cycle"]
assert "target" not in data["role_terms"]
def test_run_audit_writes_report(monkeypatch, tmp_path):
monkeypatch.setattr(role_audit, "manifests_dir", lambda: tmp_path / "manifests")
monkeypatch.setattr(
role_audit,
"call_ollama",
lambda prompt, base_url=None, model=None: '{"items":[],"proposals":[]}',
)
path, parsed, entries = role_audit.run_audit(
date(2026, 9, 12), titles=["Orthodontic Clinician I"]
)
assert path.name == "role-audit-2026-09-12.md"
assert "Role audit" in path.read_text(encoding="utf-8")
assert entries[0]["title"] == "Orthodontic Clinician I"
assert parsed["proposals"] == []
# ── Engine daily hook ────────────────────────────────────────────────────────
def test_engine_role_audit_applies_only_safe_roles(monkeypatch, tmp_path):
from gimme_job.proactive.engine import ProactiveEngine, ProactiveRunResult
from gimme_job.proactive.plan import ProactivePlan
report = tmp_path / "role-audit-2026-09-13.md"
parsed = {
"items": [],
"proposals": [
{"role": "support", "term": "surgical tech", "reason": ""},
{"role": "target", "term": "clinician", "reason": ""},
],
}
monkeypatch.setattr(
role_audit, "run_audit", lambda *a, **k: (report, parsed, [{"title": "x"}])
)
applied = {}
def fake_append(proposals, path=None):
applied["proposals"] = proposals
return tmp_path / "auto.yaml", len(proposals)
monkeypatch.setattr(role_audit, "append_auto_terms", fake_append)
engine = ProactiveEngine(global_config=None)
result = ProactiveRunResult()
engine._run_role_audit(ProactivePlan(), result)
assert result.role_audit_path == str(report)
assert [p["term"] for p in applied["proposals"]] == ["surgical tech"]
def test_engine_role_audit_disabled(monkeypatch):
from gimme_job.proactive.engine import ProactiveEngine, ProactiveRunResult
from gimme_job.proactive.plan import ProactivePlan
def boom(*a, **k):
raise AssertionError("run_audit should not be called")
monkeypatch.setattr(role_audit, "run_audit", boom)
plan = ProactivePlan()
plan.role_audit.enabled = False
engine = ProactiveEngine(global_config=None)
result = ProactiveRunResult()
engine._run_role_audit(plan, result)
assert result.role_audit_path is None
def test_engine_role_audit_skips_without_candidates(monkeypatch):
from gimme_job.proactive.engine import ProactiveEngine, ProactiveRunResult
from gimme_job.proactive.plan import ProactivePlan
def no_candidates(*a, **k):
raise ValueError("no candidates logged for this date")
monkeypatch.setattr(role_audit, "run_audit", no_candidates)
engine = ProactiveEngine(global_config=None)
result = ProactiveRunResult()
engine._run_role_audit(ProactivePlan(), result)
assert result.role_audit_path is None