-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_scoring_engine.py
More file actions
107 lines (82 loc) · 3.62 KB
/
Copy pathtest_scoring_engine.py
File metadata and controls
107 lines (82 loc) · 3.62 KB
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"""Stub scorer behavior and the activation gate's conservative contract."""
from __future__ import annotations
from openjobradar.scoring import (
GoldenCase,
StubScorer,
build_facet_context,
evaluate_activation,
get_builtin_rubric,
)
RUBRIC = get_builtin_rubric("data_analytics_ml")
PROFILE = {
"targeting": {"target_domains": ["healthcare data interoperability"]},
"candidate": {"tech_stack": ["Snowflake", "Airflow"], "skills": ["measurement design"]},
}
STRONG_POSTING = {
"title": "Healthcare Data Platform Lead",
"description": "Own Snowflake pipelines, Airflow orchestration, measurement design.",
}
WEAK_POSTING = {"title": "Barista", "description": "Espresso and pastries."}
def _results(scorer, postings):
return {pid: scorer.score(p, build_facet_context(PROFILE), RUBRIC) for pid, p in postings.items()}
def test_stub_scores_strong_posting_above_weak() -> None:
scorer = StubScorer()
ctx = build_facet_context(PROFILE)
strong = scorer.score(STRONG_POSTING, ctx, RUBRIC)
weak = scorer.score(WEAK_POSTING, ctx, RUBRIC)
assert strong.score > weak.score
assert weak.verdict == "pass"
assert strong.rationale
def test_result_provenance_fields() -> None:
result = StubScorer().score(STRONG_POSTING, {}, RUBRIC)
assert result.scorer_id == "stub-v0"
assert result.rubric_id == "data_analytics_ml"
assert set(result.facets) == {f["id"] for f in RUBRIC["facets"]}
def test_score_bounds_hold_for_garbage_input() -> None:
result = StubScorer().score({"title": "\u00e9\u00e8\u00ea" * 30}, {}, RUBRIC)
assert 0 <= result.score <= 100
def test_gate_allows_identical_replay() -> None:
scorer = StubScorer()
postings = {"strong": STRONG_POSTING, "weak": WEAK_POSTING}
results = _results(scorer, postings)
cases = [
GoldenCase("strong", results["strong"].verdict),
GoldenCase("weak", results["weak"].verdict),
]
decision = evaluate_activation(cases, results, results)
assert decision.allowed
assert decision.regressions == 0
assert decision.agreement_rate == 1.0
def test_gate_blocks_lost_alert() -> None:
from openjobradar.scoring import ScoreResult
active = {
"a": ScoreResult(85, "alert", {}, "", "r1", "s"),
"b": ScoreResult(40, "pass", {}, "", "r1", "s"),
}
candidate = {
"a": ScoreResult(55, "digest", {}, "", "r2", "s"),
"b": ScoreResult(40, "pass", {}, "", "r2", "s"),
}
cases = [GoldenCase("a", "alert"), GoldenCase("b", "pass")]
decision = evaluate_activation(cases, active, candidate)
assert not decision.allowed
assert any("regressed" in reason for reason in decision.reasons)
def test_gate_blocks_unexpected_promotion_and_low_agreement() -> None:
from openjobradar.scoring import ScoreResult
active = {"a": ScoreResult(50, "pass", {}, "", "r1", "s")}
candidate = {"a": ScoreResult(95, "alert", {}, "", "r2", "s")}
cases = [GoldenCase("a", "pass")]
decision = evaluate_activation(cases, active, candidate)
assert not decision.allowed
assert any("promotion" in reason for reason in decision.reasons)
def test_gate_requires_full_coverage() -> None:
decision = evaluate_activation([GoldenCase("missing", "alert")], {}, {})
assert not decision.allowed
assert "missing scores" in decision.reasons[0]
def test_gate_refuses_empty_golden_set() -> None:
decision = evaluate_activation([], {}, {})
assert not decision.allowed
assert "golden set is empty" in decision.reasons[0]
def test_scorer_protocol_satisfied() -> None:
from openjobradar.scoring.protocol import Scorer
assert isinstance(StubScorer(), Scorer)