Add utilities and tests for contradiction log

This commit is contained in:
Alexa Amundson
2025-12-02 21:04:13 -06:00
parent 02c3049477
commit 5cdff71361
2 changed files with 74 additions and 4 deletions

View File

@@ -7,10 +7,12 @@ The intent is to build a transparent record for later analysis.
"""
from __future__ import annotations
import json
import time
from dataclasses import dataclass, asdict
from typing import List
from pathlib import Path
from typing import List, Optional
@dataclass
@@ -22,17 +24,19 @@ class ContradictionEntry:
class ContradictionLog:
def __init__(self, path: str = "contradiction_log.jsonl") -> None:
self.path = path
self.path = Path(path)
self.path.parent.mkdir(parents=True, exist_ok=True)
def append(self, prompt: str, reply: str) -> None:
entry = ContradictionEntry(time.time(), prompt, reply)
with open(self.path, "a", encoding="utf-8") as f:
self.path.parent.mkdir(parents=True, exist_ok=True)
with self.path.open("a", encoding="utf-8") as f:
f.write(json.dumps(asdict(entry)) + "\n")
def read_all(self) -> List[ContradictionEntry]:
entries: List[ContradictionEntry] = []
try:
with open(self.path, "r", encoding="utf-8") as f:
with self.path.open("r", encoding="utf-8") as f:
for line in f:
data = json.loads(line.strip())
entries.append(ContradictionEntry(**data))
@@ -40,6 +44,27 @@ class ContradictionLog:
pass
return entries
def to_dicts(self) -> List[dict]:
"""Return log entries as dictionaries for serialization or inspection."""
return [asdict(entry) for entry in self.read_all()]
def latest(self) -> Optional[ContradictionEntry]:
"""Return the most recent log entry if available."""
entries = self.read_all()
return entries[-1] if entries else None
def summary(self) -> dict:
"""Provide a small summary about the log contents."""
entries = self.read_all()
return {
"count": len(entries),
"oldest_ts": entries[0].timestamp if entries else None,
"newest_ts": entries[-1].timestamp if entries else None,
}
def __len__(self) -> int: # pragma: no cover - simple delegation
return len(self.read_all())
if __name__ == "__main__":
# Example usage:

View File

@@ -0,0 +1,45 @@
from __future__ import annotations
from pathlib import Path
from tempfile import TemporaryDirectory
from unittest import TestCase
from unittest.mock import patch
from lucidia.contradiction_log import ContradictionLog
class ContradictionLogTest(TestCase):
def test_append_and_read_all(self) -> None:
with TemporaryDirectory() as tmp:
log_path = Path(tmp) / "logs" / "contradictions.jsonl"
log = ContradictionLog(str(log_path))
with patch("lucidia.contradiction_log.time.time", side_effect=[1000.0, 1001.5]):
log.append("prompt-one", "reply-one")
log.append("prompt-two", "reply-two")
entries = log.read_all()
self.assertEqual(len(entries), 2)
self.assertEqual(entries[0].prompt, "prompt-one")
self.assertEqual(entries[1].reply, "reply-two")
self.assertEqual(entries[0].timestamp, 1000.0)
self.assertEqual(entries[1].timestamp, 1001.5)
def test_summary_and_latest(self) -> None:
with TemporaryDirectory() as tmp:
log = ContradictionLog(str(Path(tmp) / "nested" / "log.jsonl"))
with patch("lucidia.contradiction_log.time.time", side_effect=[42.0, 84.0]):
log.append("a", "b")
log.append("c", "d")
summary = log.summary()
self.assertEqual(summary["count"], 2)
self.assertEqual(summary["oldest_ts"], 42.0)
self.assertEqual(summary["newest_ts"], 84.0)
latest = log.latest()
assert latest is not None
self.assertEqual(latest.prompt, "c")
self.assertEqual(latest.reply, "d")