Files
Shadowbroker/backend/services/infonet/tests/test_2_reputation_adapter.py
T
2026-05-01 22:56:50 -06:00

96 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Sprint 2 — InfonetReputationAdapter end-to-end coverage.
The adapter is the integration boundary every later sprint will extend.
Sprint 2 wires it to the pure functions in ``services/infonet/reputation/``.
"""
from __future__ import annotations
from services.infonet.adapters.reputation_adapter import InfonetReputationAdapter
from services.infonet.tests._chain_factory import make_event, make_market_chain
def test_adapter_zero_rep_for_unknown_node():
a = InfonetReputationAdapter(lambda: [])
assert a.oracle_rep("nobody") == 0.0
assert a.common_rep("nobody") == 0.0
assert a.oracle_rep_lifetime("nobody") == 0.0
def test_adapter_oracle_rep_breakdown_components():
base = 1_000_000.0
chain = make_market_chain(
"m1", "creator", outcome="yes",
predictions=[
{"node_id": "alice", "side": "yes", "stake_amount": 10.0},
{"node_id": "bob", "side": "no", "stake_amount": 10.0},
],
base_ts=base,
participants=5, total_stake=20.0,
)
a = InfonetReputationAdapter(lambda: chain)
bd = a.oracle_rep_breakdown("alice")
assert bd.staked_prediction_returns == 20.0
assert bd.staked_prediction_losses == 0.0
assert bd.total == 20.0
def test_adapter_uses_chain_majority_time_for_decay():
base = 1_000_000.0
chain = make_market_chain(
"m1", "creator", outcome="yes",
predictions=[{"node_id": "alice", "side": "yes", "probability_at_bet": 30.0}],
base_ts=base,
participants=5, total_stake=10.0,
)
# Add many recent events from distinct nodes to drive chain_majority_time
# well beyond the decay window.
later = base + 86400.0 * 200 # 200 days past finalize
for i in range(11):
chain.append(make_event(
"uprep", f"chatter{i}",
{"target_node_id": "alice", "target_event_id": f"e{i}"},
timestamp=later + i, sequence=1,
))
a = InfonetReputationAdapter(lambda: chain)
base_balance = a.oracle_rep("alice")
active = a.oracle_rep_active("alice")
# Within 090 days: full weight. After 90: factor 0.5. After 180: 0.25.
# 200 days → 2 periods → 0.25.
assert active < base_balance
def test_adapter_decay_factor_helper_exposes_zero_for_unknown_node():
a = InfonetReputationAdapter(lambda: [])
assert a.decay_factor("nobody") == 0.0
def test_adapter_last_successful_prediction_ts():
base = 1_000_000.0
chain = make_market_chain(
"m1", "creator", outcome="yes",
predictions=[{"node_id": "alice", "side": "yes", "probability_at_bet": 30.0}],
base_ts=base,
participants=5, total_stake=10.0,
)
a = InfonetReputationAdapter(lambda: chain)
ts = a.last_successful_prediction_ts("alice")
assert ts is not None and ts >= base
def test_adapter_callable_chain_provider_is_invoked_per_call():
"""Adapter must NOT cache the chain — fresh evaluation each call so
new events show up. Caching at the adapter is a Sprint 3+ concern."""
snapshot_calls = {"n": 0}
chain: list[dict] = []
def provider():
snapshot_calls["n"] += 1
return list(chain)
a = InfonetReputationAdapter(provider)
a.oracle_rep("x")
a.common_rep("x")
a.oracle_rep_lifetime("x")
assert snapshot_calls["n"] == 3