o2o-negosium-original/agent/tests/test_h5_harness.py

60 lines
2.3 KiB
Python

"""H5 검증 — 학습 검증 하네스 (PoC 본체).
핵심 판정(계획서 G): 학습형(qtable_ucb)이 random/static 대비 성과 우상향.
- 평균보상 우위(95%CI 분리) + '좋은 카드' 적중 우위 → 학습 루프 유효.
- 시뮬레이터 결정론(동일 seed 재현).
- 멀티테넌트 분리 실행(--tenant).
"""
import pytest
from eval_harness.buyer import HeuristicBuyer, Scenario, make_card_effectiveness
from eval_harness.runner import run
from eval_harness.simulator import run_episode
from negotiation.qtable.domain.model.q_table import QTable
from negotiation.policies.qtable_policy import UCBQTablePolicy
from tenancy.config import RewardConfig, StateConfig
def test_simulator_deterministic():
eff = make_card_effectiveness(9, seed=1)
scn = Scenario(anchor_price=800, target_price=1000)
sc, rc = StateConfig(), RewardConfig()
def one():
b = HeuristicBuyer(eff, seed=7)
p = UCBQTablePolicy(QTable(sc.state_space_size, 9))
return run_episode(p, b, scn, sc, rc, 9, learn=False).total_reward
assert one() == one() # 동일 seed → 동일 결과
def test_card_effectiveness_has_good_cards():
eff = make_card_effectiveness(9, seed=42, n_good=3)
good = [a for a, e in eff.items() if e >= 0.7]
assert len(good) >= 3 # 효과 좋은 카드 존재 → 학습 대상 신호
@pytest.mark.parametrize("tenant", ["ktcommerce", "imarketkorea"])
def test_learning_beats_baseline(tenant):
report = run("configs/exp_default.yaml", tenant)
pols = report["policies"]
q = pols["qtable_ucb"]
rnd = pols["random"]
# 평균보상 우위 + 95%CI 비중첩
assert q["mean_reward"] > rnd["mean_reward"]
assert q["mean_reward"] - q["reward_ci95"] > rnd["mean_reward"] + rnd["reward_ci95"]
# 좋은 카드 적중 우위 (학습으로 카드 우열 파악)
assert q["good_card_hit_rate"] >= rnd["good_card_hit_rate"] + 0.2
assert q["good_card_hit_rate"] >= 0.7
# 종합 판정
assert report["verdict"]["pass"] is True
def test_static_does_not_learn():
report = run("configs/exp_default.yaml", "ktcommerce")
static = report["policies"]["static"]
# 정적 정책은 항상 고정 카드 → 좋은카드 적중 학습 없음(우연 일치만)
assert static["good_card_hit_rate"] <= report["policies"]["qtable_ucb"]["good_card_hit_rate"]