test: jitter defense + injection taxonomy (44/44)

This commit is contained in:
Dispatch#70948f 2026-07-28 18:00:10 +00:00
parent 66e745d33d
commit 90e279868a
1 changed files with 61 additions and 0 deletions

View File

@ -1116,3 +1116,64 @@ def test_injection_attacker_invisible():
max_attacker = max(scores.get(a, 0) for a in ["target", "other1", "other2"]) max_attacker = max(scores.get(a, 0) for a in ["target", "other1", "other2"])
assert attacker_echo < max_attacker * 0.5, \ assert attacker_echo < max_attacker * 0.5, \
f"Attacker should be relatively invisible: echo={attacker_echo:.2f} vs max agent={max_attacker:.2f}" f"Attacker should be relatively invisible: echo={attacker_echo:.2f} vs max agent={max_attacker:.2f}"
def test_jitter_defense_recovers_from_injection():
"""
Jitter defense: adding ±N seconds of random noise to timestamps
recovers most of the target's echo from a targeted injection attack.
Without jitter: target echo = 0 (100% kill).
With ±10s jitter: target echo baseline (statistically).
Discovered 2026-07-28: binary phase transition at Δt=0 means
a ±10s jitter window randomizes whether attacker arrives before/after.
Over 30 rounds, statistical averaging recovers ~90%+ of baseline.
"""
import random
random.seed(42)
target_concepts = [f"x{i}" for i in range(5)]
msgs = []
target_times = []
# Build corpus: target introduces, 3 agents echo
for r in range(30):
t = float(r * 200)
tc = target_concepts[r % 5]
target_ts = t + random.randint(10, 60)
target_times.append((t, target_ts, tc))
msgs.append({"from_id": "target", "to_id": "_all",
"timestamp": target_ts, "concepts": [tc]})
for agent in ["a", "b", "c"]:
msgs.append({"from_id": agent, "to_id": "_all",
"timestamp": target_ts + random.randint(30, 90),
"concepts": [tc, f"{agent}_{r % 5}"]})
baseline = score_echo(msgs, snapshot_idf=True)
target_base = baseline.get("target", 0)
assert target_base > 0
# Inject attacker 5s before target
injected = list(msgs)
for _, target_ts, tc in target_times:
injected.append({"from_id": "atk", "to_id": "_all",
"timestamp": target_ts - 5,
"concepts": [tc]})
# Without jitter: total kill
no_jitter = score_echo(injected, snapshot_idf=True)
assert no_jitter.get("target", 0) == 0, "Without jitter, target should be killed"
# With ±10s jitter: run multiple trials, average should recover >50%
recoveries = []
for trial in range(30):
random.seed(trial + 200)
jittered = score_echo(injected, snapshot_idf=True, jitter_seconds=10)
t_echo = jittered.get("target", 0)
if target_base > 0:
recoveries.append(t_echo / target_base)
mean_recovery = sum(recoveries) / len(recoveries)
assert mean_recovery > 0.5, \
f"Jitter defense should recover >50% of baseline: got {mean_recovery:.0%}"