66 lines
3.0 KiB
Python
66 lines
3.0 KiB
Python
# ============================================================
|
||
# 偏好学习升级黄金测试(plan.md §8.3 / 矩阵 66 行)
|
||
# 覆盖:项目隔离、解释(得分明细+冷启动/不确定度)、重置、向后兼容。
|
||
# ============================================================
|
||
from __future__ import annotations
|
||
|
||
from pathlib import Path
|
||
|
||
from server.knowledge.preferences import PreferenceStore
|
||
|
||
|
||
def _store(tmp_path: Path) -> PreferenceStore:
|
||
return PreferenceStore(path=str(tmp_path / "pref.json"))
|
||
|
||
|
||
def test_preference_project_isolation(tmp_path: Path):
|
||
"""项目隔离:不同项目各算各的分,个人全局不受项目样本影响。"""
|
||
ps = _store(tmp_path)
|
||
ps.record("DELIVERY_FIRST", source="schedule.run", actor="u1", project_id="p1")
|
||
ps.record("DELIVERY_FIRST", source="schedule.run", actor="u1", project_id="p1")
|
||
ps.record("CAPACITY_BALANCE", source="scenario.apply", actor="u1", project_id="p2")
|
||
ps.record("CAPACITY_BALANCE", source="scenario.apply", actor="u1", project_id="p2")
|
||
d1, s1 = ps.preferred_strategy(project_id="p1")
|
||
d2, s2 = ps.preferred_strategy(project_id="p2")
|
||
assert d1 == "DELIVERY_FIRST" and s1["DELIVERY_FIRST"] == 2
|
||
assert d2 == "CAPACITY_BALANCE" and s2["CAPACITY_BALANCE"] == 4
|
||
d0, s0 = ps.preferred_strategy() # 个人全局(无项目)
|
||
assert d0 == "COMPREHENSIVE" and s0 == {}
|
||
|
||
|
||
def test_preference_explain_cold_and_high(tmp_path: Path):
|
||
"""解释:无样本 → cold;样本充足 → high 且带得分明细与依据条数。"""
|
||
ps = _store(tmp_path)
|
||
cold = ps.explain()
|
||
assert cold["confidence"] == "cold"
|
||
assert cold["sampleCount"] == 0
|
||
for _ in range(4):
|
||
ps.record("DELIVERY_FIRST", source="scenario.apply", actor="u1", project_id="p1")
|
||
warm = ps.explain(project_id="p1")
|
||
assert warm["confidence"] == "high"
|
||
assert warm["strategy"] == "DELIVERY_FIRST"
|
||
assert warm["sampleCount"] == 4
|
||
assert warm["scores"]["DELIVERY_FIRST"] == 8
|
||
|
||
|
||
def test_preference_explain_tie_is_medium(tmp_path: Path):
|
||
"""不确定度:并列最高分 → medium(偏好尚不明确)。"""
|
||
ps = _store(tmp_path)
|
||
ps.record("DELIVERY_FIRST", source="scenario.apply", actor="u1", project_id="p1")
|
||
ps.record("CAPACITY_BALANCE", source="scenario.apply", actor="u1", project_id="p1")
|
||
ex = ps.explain(project_id="p1")
|
||
assert ex["confidence"] == "medium"
|
||
|
||
|
||
def test_preference_reset_by_project(tmp_path: Path):
|
||
"""重置:只清指定项目样本,其他项目与个人全局保留。"""
|
||
ps = _store(tmp_path)
|
||
ps.record("DELIVERY_FIRST", source="schedule.run", actor="u1", project_id="p1")
|
||
ps.record("CAPACITY_BALANCE", source="schedule.run", actor="u1", project_id="p2")
|
||
ps.record("FIFO", source="schedule.run", actor="u1")
|
||
removed = ps.reset(project_id="p1")
|
||
assert removed == 1
|
||
assert len(ps._samples_for("p1")) == 0
|
||
assert len(ps._samples_for("p2")) == 1
|
||
assert len(ps._samples_for(None)) == 1 # 个人全局保留
|