Files
Timmy-time-dashboard/tests/timmy/nexus/test_persistence.py
Perplexity Computer 77cdfde3a2
Some checks failed
Tests / lint (pull_request) Failing after 46s
Tests / test (pull_request) Has been skipped
[perplexity] feat: Nexus v2 — Cognitive Awareness & Introspection Engine (#1090)
Extends the Nexus from a chat-only interface into a full cognitive
awareness space with real-time introspection, persistent sessions,
and sovereignty health monitoring.

New modules (src/timmy/nexus/):
- introspection.py — Aggregates CognitiveTracker, ThinkingEngine, and
  session analytics into a unified IntrospectionSnapshot. Surfaces mood,
  engagement, focus, commitments, and recent thoughts.
- persistence.py — SQLite-backed NexusStore so conversations survive
  process restarts. WAL mode, auto-pruning at 500 messages, session-tag
  isolation for future per-operator sessions.
- sovereignty_pulse.py — Reads the SovereigntyMetricsStore (PR #1331)
  and distils a live health pulse: per-layer sovereignty %, API
  independence rate, crystallization velocity.

Enhanced routes (src/dashboard/routes/nexus.py):
- GET  /nexus          — now serves introspection + pulse alongside chat
- POST /nexus/chat     — persists messages; tracks memory hits
- DELETE /nexus/history — clears both in-memory and SQLite stores
- GET  /nexus/introspect — JSON API for introspection + sovereignty data
- WS   /nexus/ws       — live push of cognitive state, thought stream,
                          and sovereignty pulse every 5 seconds

Enhanced template (nexus.html):
- Cognitive State panel (mood, engagement, focus, depth, commitments)
- Thought Stream viewer (5 most recent, seed type, timestamps)
- Sovereignty Pulse badge + detail panel (per-layer bars, stats)
- Session Analytics grid (message count, avg response, duration)
- WebSocket client with auto-reconnect for live updates

CSS (mission-control.css):
- Full Nexus v2 design system: pulse badges, health indicators,
  cognitive grid, thought stream cards, sovereignty bar meters,
  analytics grid, scrollable sidebar

Tests: 58 total (all green)
- 20 introspection tests (data models, snapshot, fallback, cognitive/thought readers)
- 18 persistence tests (CRUD, ordering, session tags, pruning, reopen)
- 12 sovereignty pulse tests (classify health, snapshot, API independence)
- 8 route/template tests (new panels, WebSocket script, introspect API)

Refs: #1090
2026-03-24 02:48:22 +00:00

145 lines
4.8 KiB
Python

"""Tests for the Nexus Session Persistence store."""
import pytest
from timmy.nexus.persistence import MAX_MESSAGES, NexusStore
@pytest.fixture
def store(tmp_path):
"""Provide a NexusStore backed by a temp database."""
db = tmp_path / "test_nexus.db"
s = NexusStore(db_path=db)
yield s
s.close()
class TestNexusStoreBasic:
def test_append_and_retrieve(self, store):
store.append("user", "hello")
store.append("assistant", "hi there")
history = store.get_history()
assert len(history) == 2
assert history[0]["role"] == "user"
assert history[0]["content"] == "hello"
assert history[1]["role"] == "assistant"
def test_message_count(self, store):
assert store.message_count() == 0
store.append("user", "a")
store.append("user", "b")
assert store.message_count() == 2
def test_custom_timestamp(self, store):
store.append("user", "msg", timestamp="12:34:56")
history = store.get_history()
assert history[0]["timestamp"] == "12:34:56"
def test_clear_session(self, store):
store.append("user", "a")
store.append("assistant", "b")
deleted = store.clear()
assert deleted == 2
assert store.message_count() == 0
def test_clear_empty_session(self, store):
deleted = store.clear()
assert deleted == 0
def test_clear_all(self, store):
store.append("user", "a", session_tag="s1")
store.append("user", "b", session_tag="s2")
deleted = store.clear_all()
assert deleted == 2
assert store.message_count(session_tag="s1") == 0
assert store.message_count(session_tag="s2") == 0
class TestNexusStoreOrdering:
def test_chronological_order(self, store):
for i in range(5):
store.append("user", f"msg-{i}")
history = store.get_history()
contents = [m["content"] for m in history]
assert contents == ["msg-0", "msg-1", "msg-2", "msg-3", "msg-4"]
def test_limit_parameter(self, store):
for i in range(10):
store.append("user", f"msg-{i}")
history = store.get_history(limit=3)
assert len(history) == 3
# Should be the 3 most recent
assert history[0]["content"] == "msg-7"
assert history[2]["content"] == "msg-9"
class TestNexusStoreSessionTags:
def test_session_isolation(self, store):
store.append("user", "nexus-msg", session_tag="nexus")
store.append("user", "other-msg", session_tag="other")
nexus_history = store.get_history(session_tag="nexus")
other_history = store.get_history(session_tag="other")
assert len(nexus_history) == 1
assert len(other_history) == 1
assert nexus_history[0]["content"] == "nexus-msg"
def test_clear_only_affects_target_session(self, store):
store.append("user", "a", session_tag="s1")
store.append("user", "b", session_tag="s2")
store.clear(session_tag="s1")
assert store.message_count(session_tag="s1") == 0
assert store.message_count(session_tag="s2") == 1
class TestNexusStorePruning:
def test_prune_excess_messages(self, tmp_path):
"""Inserting beyond MAX_MESSAGES should prune oldest."""
db = tmp_path / "prune_test.db"
s = NexusStore(db_path=db)
# Insert MAX_MESSAGES + 5 to trigger pruning
for i in range(MAX_MESSAGES + 5):
s.append("user", f"msg-{i}")
assert s.message_count() == MAX_MESSAGES
# Get full history — oldest remaining should be msg-5
history = s.get_history(limit=MAX_MESSAGES)
assert history[0]["content"] == "msg-5"
s.close()
class TestNexusStoreReopen:
def test_data_survives_close_reopen(self, tmp_path):
"""Data persists across store instances (simulates process restart)."""
db = tmp_path / "reopen.db"
s1 = NexusStore(db_path=db)
s1.append("user", "persistent message")
s1.close()
s2 = NexusStore(db_path=db)
history = s2.get_history()
assert len(history) == 1
assert history[0]["content"] == "persistent message"
s2.close()
class TestNexusStoreReturnedId:
def test_append_returns_row_id(self, store):
id1 = store.append("user", "first")
id2 = store.append("user", "second")
assert isinstance(id1, int)
assert id2 > id1
class TestNexusStoreClose:
def test_close_is_idempotent(self, store):
store.close()
store.close() # Should not raise
def test_operations_after_close_reconnect(self, store):
"""After close, next operation should reconnect automatically."""
store.append("user", "before close")
store.close()
# Should auto-reconnect
store.append("user", "after close")
assert store.message_count() == 2