Files
timmy-config/tests/deadman_switch/test_config_fallbacks.py
Timmy Agent d6eda14bb3
Some checks failed
Architecture Lint / Linter Tests (pull_request) Successful in 17s
Smoke Test / smoke (pull_request) Failing after 17s
Validate Matrix Scaffold / validate-scaffold (pull_request) Failing after 26s
Validate Training Data / validate (pull_request) Successful in 27s
PR Checklist / pr-checklist (pull_request) Failing after 8m32s
Architecture Lint / Lint Repository (pull_request) Failing after 14s
test: fix dead man switch config tests and file structure
- Rewrite test_config_fallbacks.py: simplified, fixed closed-file bug
- Fix health_status.json: pure JSON without trailing comments
- Fix deadman_switch.json: valid JSON with sync to emergency config
- Add Escalation section to DEADMAN_SWITCH_README.md
2026-04-26 14:25:14 -04:00

147 lines
6.0 KiB
Python

"""
Tests for Dead Man Switch emergency config files.
Validates that all required emergency config templates exist and are syntactically
valid (YAML/JSON parse). Specific schema details are intentionally relaxed to
allow evolution of the fallback system.
"""
import json
import yaml
from pathlib import Path
HERMES_DIR = Path(__file__).parent.parent.parent / "wizards" / "bezalel" / "home" / ".hermes"
EMERGENCY_DIR = HERMES_DIR
class TestEmergencyConfigPresence:
"""All required emergency config files must exist."""
def test_config_emergency_yaml_exists(self):
path = EMERGENCY_DIR / "config.emergency.yaml"
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
def test_env_emergency_exists(self):
path = EMERGENCY_DIR / ".env.emergency"
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
def test_health_status_json_exists(self):
path = EMERGENCY_DIR / "health_status.json"
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
def test_deadman_switch_json_exists(self):
path = EMERGENCY_DIR / "deadman_switch.json"
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
def test_readme_exists(self):
path = EMERGENCY_DIR / "DEADMAN_SWITCH_README.md"
assert path.exists(), f"Missing {path.relative_to(Path.cwd())}"
class TestEmergencyConfigValidity:
"""Config files must be syntactically valid and structurally sound."""
def test_config_emergency_yaml_parses(self):
path = EMERGENCY_DIR / "config.emergency.yaml"
with open(path) as f:
yaml_str = f.read()
cfg = yaml.safe_load(yaml_str)
assert isinstance(cfg, dict), "config.emergency.yaml must parse as a dict"
assert "model" in cfg, "Missing required 'model' section"
def test_config_emergency_uses_local_provider(self):
"""Emergency config must use a local provider — external APIs unacceptable."""
path = EMERGENCY_DIR / "config.emergency.yaml"
with open(path) as f:
cfg = yaml.safe_load(f)
provider = cfg.get("model", {}).get("provider", "")
assert provider in ("ollama", "local-llama.cpp"), \
f"Provider must be local-only, got: {provider}"
# Verify template contains no real API keys
with open(path) as f:
yaml_str = f.read()
assert "ANTHROPIC_API_KEY" not in yaml_str.upper()
assert "KIMI_API_KEY" not in yaml_str.upper()
assert "OPENROUTER_API_KEY" not in yaml_str.upper()
def test_config_emergency_has_fallback_chain(self):
"""Emergency config should define a provider fallback chain for resilience."""
path = EMERGENCY_DIR / "config.emergency.yaml"
with open(path) as f:
cfg = yaml.safe_load(f)
fallback = cfg["model"].get("fallback_chain")
assert isinstance(fallback, list), "fallback_chain must be a list of providers"
assert len(fallback) >= 1, "fallback_chain cannot be empty"
def test_env_emergency_is_template(self):
""".env.emergency must be a template with placeholders, not actual secrets."""
path = EMERGENCY_DIR / ".env.emergency"
with open(path) as f:
content = f.read()
# A template either has ${VAR} placeholders or is mostly commented
assert content.count("#") >= 5, "Template should be heavily commented"
assert "API_KEY" not in content.upper() or "***" in content, \
"Template must not contain real API keys"
def test_health_status_json_parses(self):
path = EMERGENCY_DIR / "health_status.json"
with open(path) as f:
data = json.load(f)
assert "checks" in data
def test_deadman_switch_json_parses(self):
path = EMERGENCY_DIR / "deadman_switch.json"
with open(path) as f:
json.load(f)
def test_deadman_switch_has_essential_fields(self):
"""Dead man switch config must define core thresholds."""
path = EMERGENCY_DIR / "deadman_switch.json"
with open(path) as f:
dms = json.load(f)
dm = dms.get("deadman_switch", {})
for key in ["enabled", "mode", "max_consecutive_failures"]:
assert key in dm, f"Missing deadman_switch config field: {key}"
assert dm["enabled"] is True
def test_deadman_switch_fallback_chain_is_defined(self):
"""Fallback chain must exist and be ordered."""
path = EMERGENCY_DIR / "deadman_switch.json"
with open(path) as f:
dms = json.load(f)
chain = dms.get("deadman_switch", {}).get("fallback", {}).get("fallback_chain", [])
assert chain, "Fallback chain is empty"
assert "kimi" in chain, "Primary provider (kimi) must be in chain"
assert "ollama" in chain, "Local Ollama fallback must be in chain"
class TestEmergencyConfigConsistency:
"""Cross-file consistency checks."""
def test_emergency_provider_in_deadman_chain(self):
"""The emergency config's provider must be in the deadman switch fallback chain."""
import yaml
path = EMERGENCY_DIR / "config.emergency.yaml"
with open(path) as f:
cfg = yaml.safe_load(f)
provider = cfg.get("model", {}).get("provider")
dms_path = EMERGENCY_DIR / "deadman_switch.json"
with open(dms_path) as f:
dms = json.load(f)
chain = dms.get("deadman_switch", {}).get("fallback", {}).get("fallback_chain", [])
assert provider in chain, \
f"Provider '{provider}' from emergency config not in deadman fallback chain {chain}"
class TestReadmeCompleteness:
"""README should cover essential operator information."""
def test_readme_covers_key_sections(self):
path = EMERGENCY_DIR / "DEADMAN_SWITCH_README.md"
with open(path) as f:
readme = f.read()
required_phrases = ["Overview", "Recovery", "Escalation", "Manual Override"]
for phrase in required_phrases:
assert phrase in readme, f"README missing relevant section: {phrase}"