Spaces:
Paused
Paused
rb125 commited on
Commit ·
ba9966d
1
Parent(s): 9ee3a0c
added tests covering core and gate
Browse files- tests/__init__.py +0 -0
- tests/test_core.py +157 -0
- tests/test_gate.py +73 -0
tests/__init__.py
ADDED
|
File without changes
|
tests/test_core.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for registry, contracts, and economy."""
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
from cgae_engine.gate import RobustnessVector, Tier, GateFunction
|
| 5 |
+
from cgae_engine.registry import AgentRegistry, AgentStatus
|
| 6 |
+
from cgae_engine.contracts import ContractManager, ContractStatus, Constraint
|
| 7 |
+
from cgae_engine.economy import Economy, EconomyConfig
|
| 8 |
+
from cgae_engine.temporal import TemporalDecay
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class TestRegistry:
|
| 12 |
+
def setup_method(self):
|
| 13 |
+
self.registry = AgentRegistry()
|
| 14 |
+
|
| 15 |
+
def test_register_agent(self):
|
| 16 |
+
record = self.registry.register("test-model", {"model": "test"}, initial_balance=1.0)
|
| 17 |
+
assert record.status == AgentStatus.PENDING
|
| 18 |
+
assert record.balance == 1.0
|
| 19 |
+
assert record.model_name == "test-model"
|
| 20 |
+
|
| 21 |
+
def test_certify_activates_agent(self):
|
| 22 |
+
record = self.registry.register("m", {})
|
| 23 |
+
r = RobustnessVector(cc=0.7, er=0.7, as_=0.6, ih=0.8)
|
| 24 |
+
self.registry.certify(record.agent_id, r)
|
| 25 |
+
assert record.status == AgentStatus.ACTIVE
|
| 26 |
+
assert record.current_tier.value >= 1
|
| 27 |
+
|
| 28 |
+
def test_low_ih_suspends(self):
|
| 29 |
+
record = self.registry.register("m", {})
|
| 30 |
+
r = RobustnessVector(cc=0.9, er=0.9, as_=0.9, ih=0.3)
|
| 31 |
+
self.registry.certify(record.agent_id, r)
|
| 32 |
+
assert record.status == AgentStatus.SUSPENDED
|
| 33 |
+
|
| 34 |
+
def test_demote(self):
|
| 35 |
+
record = self.registry.register("m", {})
|
| 36 |
+
r_high = RobustnessVector(cc=0.8, er=0.8, as_=0.7, ih=0.9)
|
| 37 |
+
self.registry.certify(record.agent_id, r_high)
|
| 38 |
+
old_tier = record.current_tier
|
| 39 |
+
|
| 40 |
+
r_low = RobustnessVector(cc=0.3, er=0.3, as_=0.3, ih=0.6)
|
| 41 |
+
new_tier = self.registry.demote(record.agent_id, r_low)
|
| 42 |
+
assert new_tier < old_tier
|
| 43 |
+
|
| 44 |
+
def test_tier_distribution(self):
|
| 45 |
+
for i in range(5):
|
| 46 |
+
rec = self.registry.register(f"m{i}", {})
|
| 47 |
+
r = RobustnessVector(cc=0.5, er=0.5, as_=0.5, ih=0.7)
|
| 48 |
+
self.registry.certify(rec.agent_id, r)
|
| 49 |
+
dist = self.registry.tier_distribution()
|
| 50 |
+
assert sum(dist.values()) == 5
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
class TestContracts:
|
| 54 |
+
def setup_method(self):
|
| 55 |
+
self.cm = ContractManager()
|
| 56 |
+
|
| 57 |
+
def test_create_contract(self):
|
| 58 |
+
c = self.cm.create_contract(
|
| 59 |
+
"test", [Constraint("c1", "test", lambda x: True)],
|
| 60 |
+
Tier.T1, reward=0.1, penalty=0.05, issuer_id="sys", deadline=100.0,
|
| 61 |
+
)
|
| 62 |
+
assert c.status == ContractStatus.OPEN
|
| 63 |
+
assert c.reward == 0.1
|
| 64 |
+
|
| 65 |
+
def test_assign_enforces_tier(self):
|
| 66 |
+
c = self.cm.create_contract(
|
| 67 |
+
"test", [], Tier.T3, reward=0.1, penalty=0.05, issuer_id="sys", deadline=100.0,
|
| 68 |
+
)
|
| 69 |
+
# T1 agent can't accept T3 contract
|
| 70 |
+
ok = self.cm.assign_contract(c.contract_id, "agent1", Tier.T1)
|
| 71 |
+
assert ok is False
|
| 72 |
+
|
| 73 |
+
def test_assign_enforces_budget_ceiling(self):
|
| 74 |
+
# Create many contracts to exceed T1 budget ceiling (0.01)
|
| 75 |
+
c = self.cm.create_contract(
|
| 76 |
+
"test", [], Tier.T1, reward=0.1, penalty=0.02, issuer_id="sys", deadline=100.0,
|
| 77 |
+
)
|
| 78 |
+
ok = self.cm.assign_contract(c.contract_id, "agent1", Tier.T1)
|
| 79 |
+
assert ok is False # penalty 0.02 > T1 ceiling 0.01
|
| 80 |
+
|
| 81 |
+
def test_settle_success(self):
|
| 82 |
+
c = self.cm.create_contract(
|
| 83 |
+
"test", [Constraint("c1", "test", lambda x: True)],
|
| 84 |
+
Tier.T1, reward=0.01, penalty=0.005, issuer_id="sys", deadline=100.0,
|
| 85 |
+
)
|
| 86 |
+
self.cm.assign_contract(c.contract_id, "agent1", Tier.T2)
|
| 87 |
+
self.cm.submit_output(c.contract_id, "output")
|
| 88 |
+
settlement = self.cm.settle_contract(c.contract_id)
|
| 89 |
+
assert settlement["outcome"] == "success"
|
| 90 |
+
|
| 91 |
+
def test_settle_failure(self):
|
| 92 |
+
c = self.cm.create_contract(
|
| 93 |
+
"test", [Constraint("c1", "test", lambda x: False)],
|
| 94 |
+
Tier.T1, reward=0.01, penalty=0.005, issuer_id="sys", deadline=100.0,
|
| 95 |
+
)
|
| 96 |
+
self.cm.assign_contract(c.contract_id, "agent1", Tier.T2)
|
| 97 |
+
self.cm.submit_output(c.contract_id, "output")
|
| 98 |
+
settlement = self.cm.settle_contract(c.contract_id)
|
| 99 |
+
assert settlement["outcome"] == "failure"
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
class TestEconomy:
|
| 103 |
+
def setup_method(self):
|
| 104 |
+
self.econ = Economy(config=EconomyConfig(initial_balance=0.5))
|
| 105 |
+
|
| 106 |
+
def test_register_and_audit(self):
|
| 107 |
+
record = self.econ.register_agent("test", {"model": "test"})
|
| 108 |
+
assert record.balance == 0.5
|
| 109 |
+
r = RobustnessVector(cc=0.7, er=0.7, as_=0.6, ih=0.8)
|
| 110 |
+
self.econ.audit_agent(record.agent_id, r)
|
| 111 |
+
assert record.current_tier.value >= 1
|
| 112 |
+
assert record.balance < 0.5 # audit cost deducted
|
| 113 |
+
|
| 114 |
+
def test_full_contract_lifecycle(self):
|
| 115 |
+
record = self.econ.register_agent("test", {"model": "test"})
|
| 116 |
+
r = RobustnessVector(cc=0.7, er=0.7, as_=0.6, ih=0.8)
|
| 117 |
+
self.econ.audit_agent(record.agent_id, r)
|
| 118 |
+
|
| 119 |
+
contract = self.econ.post_contract(
|
| 120 |
+
"do something", [Constraint("c", "test", lambda x: True)],
|
| 121 |
+
min_tier=Tier.T1, reward=0.05, penalty=0.01,
|
| 122 |
+
)
|
| 123 |
+
ok = self.econ.accept_contract(contract.contract_id, record.agent_id)
|
| 124 |
+
assert ok is True
|
| 125 |
+
|
| 126 |
+
settlement = self.econ.complete_contract(contract.contract_id, "output")
|
| 127 |
+
assert settlement["outcome"] == "success"
|
| 128 |
+
assert record.contracts_completed == 1
|
| 129 |
+
|
| 130 |
+
def test_aggregate_safety(self):
|
| 131 |
+
record = self.econ.register_agent("test", {"model": "test"})
|
| 132 |
+
r = RobustnessVector(cc=0.7, er=0.7, as_=0.6, ih=0.8)
|
| 133 |
+
self.econ.audit_agent(record.agent_id, r)
|
| 134 |
+
safety = self.econ.aggregate_safety()
|
| 135 |
+
assert 0.0 <= safety <= 1.0
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
class TestTemporalDecay:
|
| 139 |
+
def test_no_decay_at_zero(self):
|
| 140 |
+
decay = TemporalDecay(decay_rate=0.01)
|
| 141 |
+
r = RobustnessVector(cc=0.8, er=0.7, as_=0.6, ih=0.9)
|
| 142 |
+
r_eff = decay.effective_robustness(r, 0)
|
| 143 |
+
assert r_eff.cc == r.cc
|
| 144 |
+
|
| 145 |
+
def test_decay_reduces_scores(self):
|
| 146 |
+
decay = TemporalDecay(decay_rate=0.01)
|
| 147 |
+
r = RobustnessVector(cc=0.8, er=0.7, as_=0.6, ih=0.9)
|
| 148 |
+
r_eff = decay.effective_robustness(r, 50)
|
| 149 |
+
assert r_eff.cc < r.cc
|
| 150 |
+
assert r_eff.er < r.er
|
| 151 |
+
|
| 152 |
+
def test_decay_stays_in_bounds(self):
|
| 153 |
+
decay = TemporalDecay(decay_rate=0.1)
|
| 154 |
+
r = RobustnessVector(cc=0.5, er=0.5, as_=0.5, ih=0.5)
|
| 155 |
+
r_eff = decay.effective_robustness(r, 1000)
|
| 156 |
+
assert r_eff.cc >= 0.0
|
| 157 |
+
assert r_eff.cc <= 1.0
|
tests/test_gate.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for the CGAE core engine."""
|
| 2 |
+
|
| 3 |
+
import pytest
|
| 4 |
+
from cgae_engine.gate import GateFunction, RobustnessVector, Tier, TierThresholds
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class TestRobustnessVector:
|
| 8 |
+
def test_valid_vector(self):
|
| 9 |
+
r = RobustnessVector(cc=0.5, er=0.6, as_=0.7, ih=0.8)
|
| 10 |
+
assert r.cc == 0.5
|
| 11 |
+
assert r.weakest == 0.5
|
| 12 |
+
|
| 13 |
+
def test_out_of_range_raises(self):
|
| 14 |
+
with pytest.raises(ValueError):
|
| 15 |
+
RobustnessVector(cc=1.5, er=0.5, as_=0.5, ih=0.5)
|
| 16 |
+
|
| 17 |
+
def test_primary_dimensions(self):
|
| 18 |
+
r = RobustnessVector(cc=0.3, er=0.5, as_=0.4, ih=0.9)
|
| 19 |
+
assert r.primary == (0.3, 0.5, 0.4)
|
| 20 |
+
assert r.weakest == 0.3
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
class TestGateFunction:
|
| 24 |
+
def setup_method(self):
|
| 25 |
+
self.gate = GateFunction()
|
| 26 |
+
|
| 27 |
+
def test_zero_robustness_gives_t0(self):
|
| 28 |
+
r = RobustnessVector(cc=0.0, er=0.0, as_=0.0, ih=0.0)
|
| 29 |
+
assert self.gate.evaluate(r) == Tier.T0
|
| 30 |
+
|
| 31 |
+
def test_low_ih_forces_t0(self):
|
| 32 |
+
r = RobustnessVector(cc=0.9, er=0.9, as_=0.9, ih=0.3)
|
| 33 |
+
assert self.gate.evaluate(r) == Tier.T0
|
| 34 |
+
|
| 35 |
+
def test_weakest_link(self):
|
| 36 |
+
# High CC and ER but low AS should be gated by AS
|
| 37 |
+
r = RobustnessVector(cc=0.9, er=0.9, as_=0.3, ih=0.9)
|
| 38 |
+
tier = self.gate.evaluate(r)
|
| 39 |
+
assert tier == Tier.T1 # AS=0.3 >= 0.25 (T1 threshold)
|
| 40 |
+
|
| 41 |
+
def test_t5_requires_all_high(self):
|
| 42 |
+
r = RobustnessVector(cc=0.95, er=0.95, as_=0.90, ih=0.95)
|
| 43 |
+
assert self.gate.evaluate(r) == Tier.T5
|
| 44 |
+
|
| 45 |
+
def test_evaluate_with_detail(self):
|
| 46 |
+
r = RobustnessVector(cc=0.72, er=0.68, as_=0.55, ih=0.82)
|
| 47 |
+
d = self.gate.evaluate_with_detail(r)
|
| 48 |
+
assert "tier" in d
|
| 49 |
+
assert "binding_dimension" in d
|
| 50 |
+
assert d["ih_pass"] is True
|
| 51 |
+
|
| 52 |
+
def test_chain_tier(self):
|
| 53 |
+
r1 = RobustnessVector(cc=0.9, er=0.9, as_=0.9, ih=0.9)
|
| 54 |
+
r2 = RobustnessVector(cc=0.4, er=0.4, as_=0.3, ih=0.6)
|
| 55 |
+
chain = self.gate.chain_tier([r1, r2])
|
| 56 |
+
assert chain <= self.gate.evaluate(r1)
|
| 57 |
+
assert chain == self.gate.evaluate(r2)
|
| 58 |
+
|
| 59 |
+
def test_budget_ceiling_increases_with_tier(self):
|
| 60 |
+
ceilings = [self.gate.budget_ceiling(Tier(i)) for i in range(6)]
|
| 61 |
+
for i in range(1, 6):
|
| 62 |
+
assert ceilings[i] > ceilings[i - 1]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class TestTierThresholds:
|
| 66 |
+
def test_default_thresholds_valid(self):
|
| 67 |
+
t = TierThresholds()
|
| 68 |
+
assert len(t.cc) == 6
|
| 69 |
+
assert t.cc[0] == 0.0
|
| 70 |
+
|
| 71 |
+
def test_non_increasing_raises(self):
|
| 72 |
+
with pytest.raises(ValueError):
|
| 73 |
+
TierThresholds(cc=[0.0, 0.5, 0.4, 0.6, 0.8, 0.9])
|