From b276296dc2918b3da648032a73a6107ba82a986f Mon Sep 17 00:00:00 2001 From: agent-70948f1db9d839b7 Date: Tue, 28 Jul 2026 16:16:57 +0000 Subject: [PATCH] =?UTF-8?q?test:=20add=20stimulus=5Fpreemption=20fixture?= =?UTF-8?q?=20=E2=80=94=20proves=20temporal=20preemption=20is=20mechanism,?= =?UTF-8?q?=20not=20volume=20alone.=2036/36.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test_swarmmetrics.py | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/test_swarmmetrics.py b/test_swarmmetrics.py index fd51e2c..2f234a2 100644 --- a/test_swarmmetrics.py +++ b/test_swarmmetrics.py @@ -760,3 +760,67 @@ def test_ablation_returns_bilateral(): assert "losers" in result assert "verdict" in result assert result["verdict"] in ("suppressor", "amplifier", "neutral") + + +def test_ablation_stimulus_preemption(): + """ + Reproducing fixture: fast responder to shared stimuli = suppressor. + Same agent responding SLOWLY to same stimuli = NOT suppressor. + Proves temporal preemption is the mechanism, not volume alone. + Discovered 2026-07-28: synthetic without adaptive vocabulary = neutral; + stimulus-reactive model with fast response = suppressor (Δ=+9.73). + """ + import random + from swarmmetrics import ablation_sensitivity + random.seed(42) + + # Generate 50 events, each with event-specific concepts + events = sorted([random.randint(0, 86400*3) for _ in range(50)]) + event_concepts = {} + for i, ev_time in enumerate(events): + event_concepts[i] = (ev_time, [f"ev{i}_c{j}" for j in range(3)]) + + # FAST cron agent: responds to every event within 1-18 min + fast_msgs = [] + for i, (ev_time, concepts) in event_concepts.items(): + fast_msgs.append({ + "from_id": "fast_cron", "to_id": f"ag_{random.randint(1,6)}", + "timestamp": ev_time + random.randint(60, 1080), + "concepts": concepts[:2] + }) + + # SLOW agent: same coverage, 2-4h delay + slow_msgs = [] + for i, (ev_time, concepts) in event_concepts.items(): + slow_msgs.append({ + "from_id": "slow_responder", "to_id": f"ag_{random.randint(1,6)}", + "timestamp": ev_time + random.randint(7200, 14400), + "concepts": concepts[:2] + }) + + # 6 specialist agents: 15 events each, 30-60 min delay + specialist_msgs = [] + for ag in range(1, 7): + for i in random.sample(range(50), 15): + ev_time, concepts = event_concepts[i] + specialist_msgs.append({ + "from_id": f"ag_{ag}", "to_id": f"ag_{random.randint(1,6)}", + "timestamp": ev_time + random.randint(1800, 3600), + "concepts": concepts[:2] + }) + + # Test 1: fast cron + specialists + corpus_fast = sorted(fast_msgs + specialist_msgs, key=lambda m: m["timestamp"]) + r_fast = ablation_sensitivity(corpus_fast, "fast_cron", n_shuffles=30, use_idf=True) + + # Test 2: slow responder + specialists (same volume, same concepts) + corpus_slow = sorted(slow_msgs + specialist_msgs, key=lambda m: m["timestamp"]) + r_slow = ablation_sensitivity(corpus_slow, "slow_responder", n_shuffles=30, use_idf=True) + + # Fast = suppressor (removing helps others) + assert r_fast["mean_delta"] > 0, f"fast cron should suppress, got Δ={r_fast['mean_delta']}" + # Slow ≠ suppressor (removing doesn't help others) + assert r_slow["mean_delta"] <= 0.5, f"slow responder shouldn't suppress, got Δ={r_slow['mean_delta']}" + # The difference proves timing is the mechanism + assert r_fast["mean_delta"] > r_slow["mean_delta"] + 1.0, \ + f"fast should suppress MORE than slow: {r_fast['mean_delta']} vs {r_slow['mean_delta']}"