personal memory agent
1# SPDX-License-Identifier: AGPL-3.0-only
2# Copyright (c) 2026 sol pbc
3
4from __future__ import annotations
5
6import shutil
7import subprocess
8from pathlib import Path
9
10import pytest
11
12ROOT = Path(__file__).resolve().parents[1]
13DEGRADED_SVG = ROOT / "solstone" / "convey" / "static" / "sol-status" / "degraded.svg"
14WEBSOCKET_JS = ROOT / "solstone" / "convey" / "static" / "websocket.js"
15
16
17def test_degraded_status_asset_uses_red_glyph_and_keeps_ring_rays():
18 text = DEGRADED_SVG.read_text(encoding="utf-8")
19
20 assert 'stroke="#dc2626"' in text
21 assert '<circle cx="16.0" cy="18.6" r="0.7" fill="#dc2626"/>' in text
22 assert "#d97706" not in text
23 assert "#E8923A" in text
24 assert "#FFCF33" in text
25
26
27def test_websocket_status_mark_degraded_wiring():
28 text = WEBSOCKET_JS.read_text(encoding="utf-8")
29
30 assert "captureStatus === 'degraded'" in text
31 assert "degraded: 'a device needs attention'" in text
32
33
34def test_websocket_derive_status_mark_device_labels(tmp_path):
35 node = shutil.which("node")
36 if node is None:
37 pytest.skip("node is not available")
38
39 source = WEBSOCKET_JS.read_text(encoding="utf-8")
40 start = source.index(" function deriveStatusMark")
41 end = source.index("\n\n function renderStatusMark", start)
42 script = tmp_path / "derive-status-mark-test.js"
43 script.write_text(
44 """
45function assert(condition, message) {
46 if (!condition) throw new Error(message);
47}
48
49"""
50 + source[start:end]
51 + """
52
53const cases = [
54 ['connected', 'offline', false, 'error', false, 'devices offline'],
55 ['connected', 'degraded', false, 'degraded', false, 'a device needs attention'],
56 ['connected', 'stale', false, 'half', false, 'devices out of touch'],
57 ['connected', 'no_observers', false, 'paused', false, 'no devices running sol'],
58 ['connected', 'active', false, 'active', false, 'active'],
59 ['disconnected', 'active', false, 'x', false, 'disconnected'],
60 ['connected', 'unknown', false, 'question', false, 'status unknown'],
61 ['connected', 'active', true, 'bang', false, 'attention'],
62];
63
64for (const [wsState, captureStatus, hasUnviewed, variant, spin, label] of cases) {
65 const actual = deriveStatusMark(wsState, captureStatus, hasUnviewed);
66 assert(actual.variant === variant, `${label}: wrong variant ${actual.variant}`);
67 assert(actual.spin === spin, `${label}: wrong spin ${actual.spin}`);
68 assert(actual.label === label, `${label}: wrong label ${actual.label}`);
69}
70""",
71 encoding="utf-8",
72 )
73
74 subprocess.run([node, str(script)], check=True, text=True)