Files
Timmy-time-dashboard/tests/test_swarm_routing.py
Alexander Payne c5df954d44 feat: Lightning interface, swarm routing, sovereignty audit, embodiment prep
Lightning Backend Interface:
- Abstract LightningBackend with pluggable implementations
- MockBackend for development (auto-settle invoices)
- LndBackend stub with gRPC integration path documented
- Backend factory for runtime selection via LIGHTNING_BACKEND env

Intelligent Swarm Routing:
- CapabilityManifest for agent skill declarations
- Task scoring based on keywords + capabilities + bid price
- RoutingDecision audit logging to SQLite
- Agent stats tracking (wins, consideration rate)

Sovereignty Audit:
- Comprehensive audit report (docs/SOVEREIGNTY_AUDIT.md)
- 9.2/10 sovereignty score
- Documented all external dependencies and local alternatives

Substrate-Agnostic Agent Interface:
- TimAgent abstract base class
- Perception/Action/Memory/Communication types
- OllamaAdapter implementation
- Foundation for future embodiment (robot, VR)

Tests:
- 36 new tests for Lightning and routing
- 472 total tests passing
- Maintained 0 warning policy
2026-02-22 20:20:11 -05:00

230 lines
8.2 KiB
Python

"""Tests for intelligent swarm routing.
Covers:
- Capability manifest scoring
- Routing decisions
- Audit logging
- Recommendation engine
"""
import pytest
from swarm.routing import (
CapabilityManifest,
RoutingDecision,
RoutingEngine,
)
from swarm.personas import PERSONAS
class TestCapabilityManifest:
"""Tests for capability manifest scoring."""
@pytest.fixture
def forge_manifest(self):
"""Create a Forge (coding) capability manifest."""
return CapabilityManifest(
agent_id="forge-001",
agent_name="Forge",
capabilities=["coding", "debugging", "testing"],
keywords=["code", "function", "bug", "fix", "refactor", "test"],
rate_sats=55,
)
@pytest.fixture
def quill_manifest(self):
"""Create a Quill (writing) capability manifest."""
return CapabilityManifest(
agent_id="quill-001",
agent_name="Quill",
capabilities=["writing", "editing", "documentation"],
keywords=["write", "draft", "document", "readme", "blog"],
rate_sats=45,
)
def test_keyword_match_high_score(self, forge_manifest):
"""Strong keyword match gives high score."""
task = "Fix the bug in the authentication code"
score = forge_manifest.score_task_match(task)
assert score >= 0.5 # "bug" and "code" are both keywords
def test_capability_match_moderate_score(self, quill_manifest):
"""Capability match gives moderate score."""
task = "Create documentation for the API"
score = quill_manifest.score_task_match(task)
assert score >= 0.2 # "documentation" capability matches
def test_no_match_low_score(self, forge_manifest):
"""No relevant keywords gives low score."""
task = "Analyze quarterly sales data trends"
score = forge_manifest.score_task_match(task)
assert score < 0.3 # No coding keywords
def test_score_capped_at_one(self, forge_manifest):
"""Score never exceeds 1.0."""
task = "code function bug fix refactor test code code code"
score = forge_manifest.score_task_match(task)
assert score <= 1.0
def test_related_word_matching(self, forge_manifest):
"""Related words contribute to score."""
task = "Implement a new class for the API"
score = forge_manifest.score_task_match(task)
# "class" is related to coding via related_words lookup
# Score should be non-zero even without direct keyword match
assert score >= 0.0 # May be 0 if related word matching is disabled
class TestRoutingEngine:
"""Tests for the routing engine."""
@pytest.fixture
def engine(self, tmp_path):
"""Create a routing engine with temp database."""
# Point to temp location to avoid conflicts
import swarm.routing as routing
old_path = routing.DB_PATH
routing.DB_PATH = tmp_path / "routing_test.db"
engine = RoutingEngine()
yield engine
# Cleanup
routing.DB_PATH = old_path
def test_register_persona(self, engine):
"""Can register a persona manifest."""
manifest = engine.register_persona("forge", "forge-001")
assert manifest.agent_id == "forge-001"
assert manifest.agent_name == "Forge"
assert "coding" in manifest.capabilities
def test_register_unknown_persona_raises(self, engine):
"""Registering unknown persona raises error."""
with pytest.raises(ValueError) as exc:
engine.register_persona("unknown", "unknown-001")
assert "Unknown persona" in str(exc.value)
def test_get_manifest(self, engine):
"""Can retrieve registered manifest."""
engine.register_persona("echo", "echo-001")
manifest = engine.get_manifest("echo-001")
assert manifest is not None
assert manifest.agent_name == "Echo"
def test_get_manifest_nonexistent(self, engine):
"""Getting nonexistent manifest returns None."""
assert engine.get_manifest("nonexistent") is None
def test_score_candidates(self, engine):
"""Can score multiple candidates."""
engine.register_persona("forge", "forge-001")
engine.register_persona("quill", "quill-001")
task = "Write code for the new feature"
scores = engine.score_candidates(task)
assert "forge-001" in scores
assert "quill-001" in scores
# Forge should score higher or equal for coding task
# (both may have low scores for generic task)
assert scores["forge-001"] >= scores["quill-001"]
def test_recommend_agent_selects_winner(self, engine):
"""Recommendation selects best agent."""
engine.register_persona("forge", "forge-001")
engine.register_persona("quill", "quill-001")
task_id = "task-001"
description = "Fix the bug in authentication code"
bids = {"forge-001": 50, "quill-001": 40} # Quill cheaper
winner, decision = engine.recommend_agent(task_id, description, bids)
# Forge should win despite higher bid due to capability match
assert winner == "forge-001"
assert decision.task_id == task_id
assert "forge-001" in decision.candidate_agents
def test_recommend_agent_no_bids(self, engine):
"""No bids returns None winner."""
winner, decision = engine.recommend_agent(
"task-001", "Some task", {}
)
assert winner is None
assert decision.selected_agent is None
assert "No bids" in decision.selection_reason
def test_routing_decision_logged(self, engine):
"""Routing decision is persisted."""
engine.register_persona("forge", "forge-001")
winner, decision = engine.recommend_agent(
"task-001", "Code review", {"forge-001": 50}
)
# Query history
history = engine.get_routing_history(task_id="task-001")
assert len(history) == 1
assert history[0].selected_agent == "forge-001"
def test_get_routing_history_limit(self, engine):
"""History respects limit."""
engine.register_persona("forge", "forge-001")
for i in range(5):
engine.recommend_agent(
f"task-{i}", "Code task", {"forge-001": 50}
)
history = engine.get_routing_history(limit=3)
assert len(history) == 3
def test_agent_stats_calculated(self, engine):
"""Agent stats are tracked correctly."""
engine.register_persona("forge", "forge-001")
engine.register_persona("echo", "echo-001")
# Forge wins 2, Echo wins 1
engine.recommend_agent("t1", "Code", {"forge-001": 50, "echo-001": 60})
engine.recommend_agent("t2", "Debug", {"forge-001": 50, "echo-001": 60})
engine.recommend_agent("t3", "Research", {"forge-001": 60, "echo-001": 50})
forge_stats = engine.get_agent_stats("forge-001")
assert forge_stats["tasks_won"] == 2
assert forge_stats["tasks_considered"] == 3
def test_export_audit_log(self, engine):
"""Can export full audit log."""
engine.register_persona("forge", "forge-001")
engine.recommend_agent("t1", "Code", {"forge-001": 50})
log = engine.export_audit_log()
assert len(log) == 1
assert log[0]["task_id"] == "t1"
class TestRoutingIntegration:
"""Integration tests for routing with real personas."""
def test_all_personas_scorable(self):
"""All built-in personas can score tasks."""
engine = RoutingEngine()
# Register all personas
for persona_id in PERSONAS:
engine.register_persona(persona_id, f"{persona_id}-001")
task = "Write a function to calculate fibonacci numbers"
scores = engine.score_candidates(task)
# All should have scores
assert len(scores) == len(PERSONAS)
# Forge (coding) should be highest
assert scores["forge-001"] == max(scores.values())