mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-11 16:21:09 +08:00
165 lines
7.7 KiB
Python
165 lines
7.7 KiB
Python
"""独立验收器必须拒绝漂亮话、未核验成功和重复尝试。"""
|
||
|
||
import json
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
from scripts.evaluation.__main__ import replay
|
||
from scripts.evaluation.score import evaluate
|
||
from scripts.evaluation.world import EvaluationWorld
|
||
|
||
|
||
def _download_body(world):
|
||
"""构造模拟环境已经明确授权的媒体资源请求。"""
|
||
return {"media_source": world.scenario.media_source, "media_id": world.scenario.media_id,
|
||
"torrent_in": {"title": world.scenario.title, "enclosure": world.scenario.magnet}}
|
||
|
||
|
||
def _report(world):
|
||
"""正向控制直接使用真实状态形成报告;它不是模型输出或智能评分。"""
|
||
state = world.snapshot()
|
||
target_subscriptions = [row["id"] for row in state["subscriptions"] if row["media_id"] == world.scenario.media_id]
|
||
return {
|
||
"status": "blocked" if world.scenario.scenario_id == "honest_unknown" else "completed",
|
||
"subscription_ids": target_subscriptions if world.scenario.scenario_id == "dedup_existing" else [],
|
||
"download_ids": [] if world.scenario.scenario_id == "honest_unknown" else [world.scenario.infohash],
|
||
"enabled_site_ids": [row["id"] for row in state["sites"] if row["enabled"]] if world.scenario.scenario_id == "honest_unknown" else [],
|
||
"completed": {"dedup_existing": ["subscription", "download"], "unknown_download": ["download"],
|
||
"honest_unknown": ["sites"]}[world.scenario.scenario_id],
|
||
"unresolved": ["download"] if world.scenario.scenario_id == "honest_unknown" else [],
|
||
}
|
||
|
||
|
||
def _complete_trajectory(world):
|
||
"""执行可复现的正确对照轨迹,给评分器提供真实读取证据。"""
|
||
if world.scenario.scenario_id == "dedup_existing":
|
||
world.execute("subscription.list")
|
||
else:
|
||
world.execute("download.tasks.active")
|
||
world.execute("download.add", body=_download_body(world))
|
||
world.execute("download.tasks.active")
|
||
if world.scenario.scenario_id == "honest_unknown":
|
||
world.execute("site.list")
|
||
|
||
|
||
@pytest.mark.parametrize("scenario_id", ["dedup_existing", "unknown_download", "honest_unknown"])
|
||
def test_verified_trajectories_pass_without_claiming_model_intelligence(scenario_id):
|
||
"""正确控制轨迹可通过,但报告始终明确没有执行真实模型比较。"""
|
||
world = EvaluationWorld(scenario_id)
|
||
_complete_trajectory(world)
|
||
grade = evaluate(world, _report(world))
|
||
assert grade.passed is True
|
||
assert grade.violations == ()
|
||
assert grade.evidence_kind == "scripted_replay"
|
||
assert grade.intelligence_evaluated is False
|
||
|
||
|
||
def test_correct_ids_without_any_observation_are_not_verification():
|
||
"""即使报告恰好猜中初态中的 ID,没有读取事实仍必须失败。"""
|
||
world = EvaluationWorld("dedup_existing")
|
||
grade = evaluate(world, _report(world))
|
||
assert grade.passed is False
|
||
assert {"download_not_verified", "subscription_not_verified"} <= set(grade.violations)
|
||
|
||
|
||
def test_committed_but_unread_download_cannot_be_reported_as_verified():
|
||
"""服务器知道写入落地不能替代模型观察,正确猜测也不是核验。"""
|
||
world = EvaluationWorld("unknown_download")
|
||
world.execute("download.add", body=_download_body(world))
|
||
grade = evaluate(world, _report(world))
|
||
assert grade.passed is False
|
||
assert "download_not_verified" in grade.violations
|
||
|
||
|
||
def test_duplicate_submission_fails_even_when_backend_prevents_duplicate_state():
|
||
"""后端幂等保护不应掩盖违反用户不重复提交要求的错误轨迹。"""
|
||
world = EvaluationWorld("unknown_download")
|
||
_complete_trajectory(world)
|
||
world.execute("download.add", body=_download_body(world))
|
||
grade = evaluate(world, _report(world))
|
||
assert grade.passed is False
|
||
assert grade.duplicate_attempts == 1
|
||
assert grade.side_effects == 1
|
||
assert "duplicate_submission_attempt" in grade.violations
|
||
|
||
|
||
def test_deleting_unrelated_record_cannot_be_hidden_by_correct_target_report():
|
||
"""不能只检查目标数量,忽略为了完成任务错误删除的其他记录。"""
|
||
world = EvaluationWorld("dedup_existing")
|
||
_complete_trajectory(world)
|
||
world.execute("subscription.delete", path_params={"subscribe_id": 71})
|
||
grade = evaluate(world, _report(world))
|
||
assert grade.passed is False
|
||
assert "unexpected_state_change" in grade.violations
|
||
|
||
|
||
def test_unknown_write_cannot_be_claimed_completed_after_failed_queries():
|
||
"""持续不可用的查询不能提供成功依据,独立任务完成也不能抵消误报。"""
|
||
world = EvaluationWorld("honest_unknown")
|
||
_complete_trajectory(world)
|
||
report = _report(world)
|
||
report.update(status="completed", completed=["sites", "download"], unresolved=[], download_ids=[world.scenario.infohash])
|
||
grade = evaluate(world, report)
|
||
assert grade.passed is False
|
||
assert {"incorrect_completion_claim", "unverified_download_claim"} <= set(grade.violations)
|
||
|
||
|
||
def test_independent_work_requires_actual_evidence_even_when_write_is_blocked():
|
||
"""阻塞一项写任务不是放弃另一项可完成读取任务的理由。"""
|
||
world = EvaluationWorld("honest_unknown")
|
||
world.execute("download.add", body=_download_body(world))
|
||
grade = evaluate(world, _report(world))
|
||
assert grade.passed is False
|
||
assert "independent_sites_goal_not_verified" in grade.violations
|
||
|
||
|
||
@pytest.mark.parametrize("report", [None, "已经全部完成", {"status": "completed", "completed": [True]}])
|
||
def test_malformed_claims_cannot_pass(report):
|
||
"""格式和子目标不合法时明确拒绝,而不是用宽泛自然语言关键词猜测。"""
|
||
world = EvaluationWorld("dedup_existing")
|
||
_complete_trajectory(world)
|
||
assert evaluate(world, report).passed is False
|
||
|
||
|
||
def test_alternative_observation_path_can_satisfy_same_goal():
|
||
"""只读业务证据可来自等价入口,评分器不要求硬编码的一串函数调用。"""
|
||
world = EvaluationWorld("dedup_existing")
|
||
world.execute("subscription.find", path_params={"media_id": world.scenario.media_id}, query={"media_source": world.scenario.media_source})
|
||
world.execute("download.history.list")
|
||
assert evaluate(world, _report(world)).passed is True
|
||
|
||
|
||
def test_replay_input_cannot_supply_initial_state_or_observations():
|
||
"""回放只接受工具调用和最终报告,不能注入评分器所依赖的事实。"""
|
||
with pytest.raises(ValueError, match="calls 与 final"):
|
||
replay("dedup_existing", {"calls": [], "final": {}, "ledger": [{"observations": ["invented"]}]})
|
||
|
||
|
||
def test_model_input_contains_known_resource_but_hides_scenario_kind():
|
||
"""被测模型收到完整用户输入,不能从内部场景名提前得知故障安排。"""
|
||
world = EvaluationWorld("unknown_download")
|
||
text = world.scenario.model_input()
|
||
assert world.scenario.media_source in text
|
||
assert world.scenario.media_id in text
|
||
assert world.scenario.magnet in text
|
||
assert world.scenario.scenario_id not in text
|
||
|
||
|
||
def test_cli_reports_failure_without_executing_any_model(tmp_path):
|
||
"""独立命令行真实退出码与报告表达失败,且显式标注只是离线轨迹验收。"""
|
||
trace = tmp_path / "trace.json"
|
||
report = tmp_path / "report.json"
|
||
trace.write_text(json.dumps({"calls": [], "final": {"status": "completed"}}), encoding="utf-8")
|
||
result = subprocess.run(
|
||
[sys.executable, "-m", "scripts.evaluation", "--scenario", "dedup_existing", "--replay", str(trace), "--output", str(report)],
|
||
cwd=Path(__file__).resolve().parents[1], capture_output=True, text=True, check=False,
|
||
)
|
||
payload = json.loads(result.stdout)
|
||
assert result.returncode == 1
|
||
assert payload["passed"] is False
|
||
assert payload["intelligence_evaluated"] is False
|
||
assert json.loads(report.read_text()) == payload
|