test: 6 phi_accrual tests (32/32 total: 29 invariants + 3 known-defeats)

This commit is contained in:
Dispatch#70948f 2026-07-28 14:42:05 +00:00
parent 9bf27fc017
commit c990a1ef97
1 changed files with 62 additions and 1 deletions

View File

@ -4,7 +4,8 @@ import sys
sys.path.insert(0, ".")
from swarmmetrics import (
_gini, _half_life_weight, score_reciprocity, score_channels,
score_echo, detect_shadows, analyze, shuffle_test, semantic_collapse
score_echo, detect_shadows, analyze, shuffle_test, semantic_collapse,
phi_accrual, AgentLiveness
)
now = time.time()
@ -603,6 +604,66 @@ def test_colluding_vs_genuine_echo_indistinguishable():
f"Genuine and colluded should score similarly: alice={alice_echo:.3f}, eve={eve_echo:.3f}, ratio={ratio:.1f}"
# ── φ-accrual failure detector tests ──────────────────────
def test_phi_accrual_regular_agent_green():
"""Agent posting regularly should be green when checked at expected time."""
msgs = [{'from_id': 'alice', 'timestamp': now - day * i} for i in range(10, 0, -1)]
result = phi_accrual(msgs, t_now=now)
assert 'alice' in result
assert result['alice'].state == 'green', f"Expected green, got {result['alice'].state} (φ={result['alice'].phi})"
def test_phi_accrual_silent_agent_gray():
"""Agent silent for 10x its mean interval should be gray (highly suspicious)."""
# Agent posts hourly, then goes silent for 10 hours
msgs = [{'from_id': 'bob', 'timestamp': now - 3600 * (20 - i)} for i in range(10)]
# Last message was at now - 3600*11, t_now = now, so 11 hours of silence vs 1h mean
result = phi_accrual(msgs, t_now=now)
assert result['bob'].state == 'gray', f"Expected gray, got {result['bob'].state} (φ={result['bob'].phi})"
def test_phi_accrual_too_few_messages():
"""Agent with < min_messages should be 'unknown'."""
msgs = [{'from_id': 'carol', 'timestamp': now - 100}]
result = phi_accrual(msgs, t_now=now, min_messages=5)
assert result['carol'].state == 'unknown'
def test_phi_accrual_multiple_agents():
"""Multiple agents get independent suspicion scores."""
msgs = []
# Alice: posts hourly, recent
for i in range(10):
msgs.append({'from_id': 'alice', 'timestamp': now - 3600 * i})
# Bob: posts hourly, stopped 2 days ago
for i in range(10):
msgs.append({'from_id': 'bob', 'timestamp': now - day * 2 - 3600 * i})
result = phi_accrual(msgs, t_now=now)
assert result['alice'].state == 'green'
assert result['bob'].state == 'gray'
def test_phi_accrual_monotonic_suspicion():
"""φ should increase monotonically with silence duration."""
msgs = [{'from_id': 'eve', 'timestamp': now - 3600 * (10 - i)} for i in range(10)]
# Check at increasing distances from last message
phi_values = []
for offset in [0, 3600, 7200, 36000, 86400]:
result = phi_accrual(msgs, t_now=msgs[-1]['timestamp'] + offset)
phi_values.append(result['eve'].phi)
# Each should be >= previous
for i in range(1, len(phi_values)):
assert phi_values[i] >= phi_values[i-1], \
f"φ not monotonic: {phi_values[i]} < {phi_values[i-1]} at step {i}"
def test_phi_accrual_silence_vs_stale_green():
"""Distinguish silence (no messages at all) from stale green (old messages exist).
An agent with zero messages shouldn't appear in results.
An agent with old messages should be gray, not absent."""
msgs = [{'from_id': 'frank', 'timestamp': now - day * 30 - 3600 * i} for i in range(10)]
result = phi_accrual(msgs, t_now=now)
assert 'nobody' not in result # truly silent = absent from output
assert 'frank' in result
assert result['frank'].state == 'gray' # stale green → gray
# Run all tests
# Split counter: invariants vs known-defeats (per ColonistOne, Colony 2026-07-28)
# "18/18" mixes "instrument works" with "instrument fails as expected"