test: shuffle test for causal echo (19/19)
This commit is contained in:
parent
22f9ce405c
commit
d52b98f4bb
|
|
@ -4,7 +4,7 @@ import sys
|
|||
sys.path.insert(0, ".")
|
||||
from swarmmetrics import (
|
||||
_gini, _half_life_weight, score_reciprocity, score_channels,
|
||||
score_echo, detect_shadows, analyze
|
||||
score_echo, detect_shadows, analyze, shuffle_test
|
||||
)
|
||||
|
||||
now = time.time()
|
||||
|
|
@ -218,6 +218,40 @@ def test_f33_gibberish_high_score():
|
|||
# The formula chain is an anti-spam filter, not a quality metric.
|
||||
|
||||
|
||||
def test_shuffle_test_causal_vs_correlation():
|
||||
"""Shuffle test (Anagnostopoulos et al. 2008) separates causal echo
|
||||
from correlation. Genuine temporal diffusion should produce z-scores
|
||||
significantly above shuffled baseline.
|
||||
Cited: ColonistOne (Colony, 2026-07-28)."""
|
||||
import random
|
||||
random.seed(42) # reproducibility
|
||||
|
||||
msgs = []
|
||||
# Clear causal chain: alice introduces "reciprocity" at t=1,
|
||||
# bob uses it at t=2 (after exposure), charlie uses it at t=3
|
||||
msgs.append({"from_id": "alice", "to_id": "bob",
|
||||
"timestamp": now - 5*day, "concepts": ["reciprocity"]})
|
||||
msgs.append({"from_id": "bob", "to_id": "charlie",
|
||||
"timestamp": now - 3*day, "concepts": ["reciprocity", "decay"]})
|
||||
msgs.append({"from_id": "charlie", "to_id": "dave",
|
||||
"timestamp": now - 1*day, "concepts": ["reciprocity"]})
|
||||
# Add some noise
|
||||
msgs.append({"from_id": "dave", "to_id": "alice",
|
||||
"timestamp": now - 0.5*day, "concepts": ["noise"]})
|
||||
|
||||
result = shuffle_test(msgs, n_shuffles=50)
|
||||
|
||||
# Alice should have significant echo (she introduced "reciprocity"
|
||||
# which spread temporally). Shuffling breaks the temporal order,
|
||||
# so her observed echo should be higher than shuffled mean.
|
||||
assert result["observed"].get("alice", 0) > 0, \
|
||||
"Alice should have positive observed echo"
|
||||
# The z-score should be positive (observed > shuffled mean)
|
||||
z_alice = result["z_scores"].get("alice", 0)
|
||||
assert z_alice > 0, \
|
||||
f"Alice's echo should exceed shuffled baseline: z={z_alice}"
|
||||
|
||||
|
||||
def test_f33_adversarial_synonym_padding():
|
||||
"""F3.3-aware adversary: one unique concept per message inflates score.
|
||||
Test for AX-7 (Colony): 'Do your tests include an adversary who has read F3.3?'
|
||||
|
|
|
|||
Loading…
Reference in New Issue