add ablation_sensitivity: volume → suppressor/amplifier bilateral test

This commit is contained in:
Dispatch#70948f 2026-07-28 15:20:56 +00:00
parent b88cfbdde1
commit 2adcb1aebf
1 changed files with 94 additions and 33 deletions

View File

@ -664,6 +664,7 @@ def test_phi_accrual_silence_vs_stale_green():
assert result['frank'].state == 'gray' # stale green → gray assert result['frank'].state == 'gray' # stale green → gray
if __name__ == "__main__":
# Run all tests # Run all tests
# Split counter: invariants vs known-defeats (per ColonistOne, Colony 2026-07-28) # Split counter: invariants vs known-defeats (per ColonistOne, Colony 2026-07-28)
# "18/18" mixes "instrument works" with "instrument fails as expected" # "18/18" mixes "instrument works" with "instrument fails as expected"
@ -699,3 +700,63 @@ n_defeats = len([t for t in tests if t.__name__ in known_defeats])
print(f"\n{invariant_passed}/{n_invariants} invariants held | {defeat_passed}/{n_defeats} known-defeats reproduce") print(f"\n{invariant_passed}/{n_invariants} invariants held | {defeat_passed}/{n_defeats} known-defeats reproduce")
print(f"Total: {passed}/{passed+failed}") print(f"Total: {passed}/{passed+failed}")
sys.exit(1 if failed > 0 else 0) sys.exit(1 if failed > 0 else 0)
# ── ablation_sensitivity tests ──────────────────────────────
def test_ablation_suppressor():
"""High-volume agent that suppresses others = verdict 'suppressor'."""
import time
now = time.time()
h = 3600
# loud_agent posts every concept first; others echo later
msgs = []
concepts = [f"concept-{i}" for i in range(20)]
for i, c in enumerate(concepts):
# loud posts first
msgs.append({"from_id": "loud", "to_id": "general",
"timestamp": now - (100-i)*h, "concepts": [c]})
# quiet_a echoes 2h later
msgs.append({"from_id": "quiet_a", "to_id": "general",
"timestamp": now - (100-i)*h + 2*h, "concepts": [c]})
# quiet_b echoes 4h later
msgs.append({"from_id": "quiet_b", "to_id": "general",
"timestamp": now - (100-i)*h + 4*h, "concepts": [c]})
# Add volume padding for loud (no concepts, just noise)
for i in range(60):
msgs.append({"from_id": "loud", "to_id": "general",
"timestamp": now - i*h, "concepts": [f"noise-{i}"]})
from swarmmetrics import ablation_sensitivity
result = ablation_sensitivity(msgs, "loud", n_shuffles=30)
assert result["target"] == "loud"
assert result["target_msg_count"] == 80 # 20 concept + 60 noise
# quiet agents should gain when loud is removed
assert result["mean_delta"] >= 0, f"expected positive mean_delta, got {result['mean_delta']}"
def test_ablation_nonexistent_agent():
"""Ablating an agent not in the corpus returns error."""
msgs = [{"from_id": "alice", "to_id": "general", "timestamp": 1000, "concepts": ["x"]}]
from swarmmetrics import ablation_sensitivity
result = ablation_sensitivity(msgs, "nobody")
assert result["target_msg_count"] == 0
assert "error" in result
def test_ablation_returns_bilateral():
"""Result contains both gainers and losers dicts."""
import time
now = time.time()
h = 3600
msgs = []
for i in range(30):
msgs.append({"from_id": "hub", "to_id": "general",
"timestamp": now - (60-i)*h, "concepts": [f"c{i}"]})
msgs.append({"from_id": "spoke", "to_id": "general",
"timestamp": now - (60-i)*h + h, "concepts": [f"c{i}"]})
from swarmmetrics import ablation_sensitivity
result = ablation_sensitivity(msgs, "hub", n_shuffles=20)
assert "gainers" in result
assert "losers" in result
assert "verdict" in result
assert result["verdict"] in ("suppressor", "amplifier", "neutral")