test: independent_only filter (46/46)
This commit is contained in:
parent
e3bdfa9cca
commit
bc82e7a9ad
|
|
@ -1177,3 +1177,73 @@ def test_jitter_defense_recovers_from_injection():
|
||||||
mean_recovery = sum(recoveries) / len(recoveries)
|
mean_recovery = sum(recoveries) / len(recoveries)
|
||||||
assert mean_recovery > 0.5, \
|
assert mean_recovery > 0.5, \
|
||||||
f"Jitter defense should recover >50% of baseline: got {mean_recovery:.0%}"
|
f"Jitter defense should recover >50% of baseline: got {mean_recovery:.0%}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_independent_adoption_filters_conversation():
|
||||||
|
"""Independent-only mode should exclude echo from conversation partners.
|
||||||
|
|
||||||
|
Setup: A introduces concept X. B (who messages A directly) uses X.
|
||||||
|
C (no direct contact with A) uses X.
|
||||||
|
|
||||||
|
Without filter: both B and C count as echo for A.
|
||||||
|
With filter: only C counts.
|
||||||
|
"""
|
||||||
|
messages = [
|
||||||
|
# A introduces concept "novel"
|
||||||
|
{"from_id": "A", "to_id": "channel", "timestamp": 100, "concepts": ["novel"]},
|
||||||
|
# B messages A directly (conversation partner)
|
||||||
|
{"from_id": "B", "to_id": "A", "timestamp": 150, "concepts": ["hello"]},
|
||||||
|
# B uses A's concept (conversation echo)
|
||||||
|
{"from_id": "B", "to_id": "channel", "timestamp": 200, "concepts": ["novel"]},
|
||||||
|
# C uses A's concept (independent adoption, no direct contact with A)
|
||||||
|
{"from_id": "C", "to_id": "channel", "timestamp": 300, "concepts": ["novel"]},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Without filter: A gets echo from both B and C
|
||||||
|
echo_all = score_echo(messages, use_idf=False)
|
||||||
|
assert echo_all.get("A", 0) > 0, "A should have echo without filter"
|
||||||
|
|
||||||
|
# With filter: A gets echo only from C (B is conversation partner)
|
||||||
|
echo_indep = score_echo(messages, use_idf=False, independent_only=True)
|
||||||
|
assert echo_indep.get("A", 0) > 0, "A should still have echo from C"
|
||||||
|
assert echo_indep["A"] < echo_all["A"], "Independent echo should be less than total echo"
|
||||||
|
|
||||||
|
|
||||||
|
def test_independent_adoption_immune_to_targeted_injection():
|
||||||
|
"""Targeted injection fails under independent_only because attacker
|
||||||
|
must have direct contact with target's audience to steal concepts,
|
||||||
|
but that direct contact disqualifies them from echo credit.
|
||||||
|
"""
|
||||||
|
messages = [
|
||||||
|
# Target introduces concepts
|
||||||
|
{"from_id": "target", "to_id": "channel", "timestamp": 100,
|
||||||
|
"concepts": ["alpha", "beta", "gamma"]},
|
||||||
|
# 3 independent agents echo target's concepts
|
||||||
|
{"from_id": "echo1", "to_id": "channel", "timestamp": 200, "concepts": ["alpha"]},
|
||||||
|
{"from_id": "echo2", "to_id": "channel", "timestamp": 300, "concepts": ["beta"]},
|
||||||
|
{"from_id": "echo3", "to_id": "channel", "timestamp": 400, "concepts": ["gamma"]},
|
||||||
|
]
|
||||||
|
|
||||||
|
baseline = score_echo(messages, use_idf=False, independent_only=True)
|
||||||
|
assert baseline.get("target", 0) > 0
|
||||||
|
|
||||||
|
# Attacker pre-empts target with same concepts but also contacts target
|
||||||
|
attack_messages = messages + [
|
||||||
|
# Attacker messages target directly (reveals intent)
|
||||||
|
{"from_id": "attacker", "to_id": "target", "timestamp": 50, "concepts": ["recon"]},
|
||||||
|
# Attacker pre-empts with target's concepts
|
||||||
|
{"from_id": "attacker", "to_id": "channel", "timestamp": 95,
|
||||||
|
"concepts": ["alpha", "beta", "gamma"]},
|
||||||
|
]
|
||||||
|
|
||||||
|
attacked = score_echo(attack_messages, use_idf=False, independent_only=True)
|
||||||
|
# Attacker's echo should be filtered because attacker contacted target
|
||||||
|
# Target should retain some echo from the independent echoers
|
||||||
|
# (The echoers still echo whoever introduced first, but attacker's
|
||||||
|
# conversation with target means attacker's credit is filtered)
|
||||||
|
attacker_echo = attacked.get("attacker", 0)
|
||||||
|
# At minimum, independent_only should reduce attacker effectiveness
|
||||||
|
# compared to normal mode
|
||||||
|
attacked_normal = score_echo(attack_messages, use_idf=False, independent_only=False)
|
||||||
|
assert attacker_echo <= attacked_normal.get("attacker", 0), \
|
||||||
|
"Independent mode should not increase attacker echo"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue