Part of #1258 — memory decay system. - vitality: float 0.0-1.0 (default 1.0) - last_accessed: ISO datetime of last access Also ensures updated_at and content_hash fields from main are present.
64 lines
2.3 KiB
Python
64 lines
2.3 KiB
Python
"""Archive entry model for Mnemosyne.
|
|
|
|
Each entry is a node in the holographic graph — a piece of meaning
|
|
with metadata, content, and links to related entries.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime, timezone
|
|
from typing import Optional
|
|
import uuid
|
|
|
|
|
|
def _compute_content_hash(title: str, content: str) -> str:
|
|
"""Compute SHA-256 of title+content for deduplication."""
|
|
raw = f"{title}\x00{content}".encode("utf-8")
|
|
return hashlib.sha256(raw).hexdigest()
|
|
|
|
|
|
@dataclass
|
|
class ArchiveEntry:
|
|
"""A single node in the Mnemosyne holographic archive."""
|
|
|
|
id: str = field(default_factory=lambda: str(uuid.uuid4()))
|
|
title: str = ""
|
|
content: str = ""
|
|
source: str = "" # "mempalace", "event", "manual", etc.
|
|
source_ref: Optional[str] = None # original MemPalace ID, event URI, etc.
|
|
topics: list[str] = field(default_factory=list)
|
|
metadata: dict = field(default_factory=dict)
|
|
created_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
|
|
updated_at: Optional[str] = None # Set on mutation; None means same as created_at
|
|
links: list[str] = field(default_factory=list) # IDs of related entries
|
|
content_hash: Optional[str] = None # SHA-256 of title+content for dedup
|
|
vitality: float = 1.0 # 0.0 (dead) to 1.0 (fully alive)
|
|
last_accessed: Optional[str] = None # ISO datetime of last access; None = never accessed
|
|
|
|
def __post_init__(self):
|
|
if self.content_hash is None:
|
|
self.content_hash = _compute_content_hash(self.title, self.content)
|
|
|
|
def to_dict(self) -> dict:
|
|
return {
|
|
"id": self.id,
|
|
"title": self.title,
|
|
"content": self.content,
|
|
"source": self.source,
|
|
"source_ref": self.source_ref,
|
|
"topics": self.topics,
|
|
"metadata": self.metadata,
|
|
"created_at": self.created_at,
|
|
"updated_at": self.updated_at,
|
|
"links": self.links,
|
|
"content_hash": self.content_hash,
|
|
"vitality": self.vitality,
|
|
"last_accessed": self.last_accessed,
|
|
}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: dict) -> ArchiveEntry:
|
|
return cls(**{k: v for k, v in data.items() if k in cls.__dataclass_fields__})
|