Initial SFERA platform baseline

This commit is contained in:
2026-05-16 19:03:49 +03:00
commit 3b845c8fce
282 changed files with 55045 additions and 0 deletions
@@ -0,0 +1,172 @@
from __future__ import annotations
from datetime import datetime, timezone
import json
from pydantic import BaseModel, Field
from sir import SemanticNode, SirSnapshot, stable_hash
class SemanticObjectVersion(BaseModel):
version_id: str
lineage_id: str
semantic_id: str
object_hash: str
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
task_id: str | None = None
session_id: str | None = None
parent_version_id: str | None = None
payload: dict = Field(default_factory=dict)
class SemanticObjectDiffEntry(BaseModel):
path: str
kind: str
before: object | None = None
after: object | None = None
class SemanticObjectDiff(BaseModel):
from_version_id: str
to_version_id: str
lineage_id: str
changed: bool
entries: list[SemanticObjectDiffEntry] = Field(default_factory=list)
class SemanticObjectChange(BaseModel):
change_kind: str
diff: SemanticObjectDiff
class InMemoryObjectVersionStore:
def __init__(self) -> None:
self._versions_by_lineage: dict[str, list[SemanticObjectVersion]] = {}
def append_node_version(
self,
node: SemanticNode,
*,
task_id: str | None = None,
session_id: str | None = None,
) -> SemanticObjectVersion:
previous = self.latest(node.lineage_id)
payload = node.model_dump(mode="json")
object_hash = stable_hash(json.dumps(payload, ensure_ascii=False, sort_keys=True))
version = SemanticObjectVersion(
version_id=f"version.{node.lineage_id}.{object_hash}",
lineage_id=node.lineage_id,
semantic_id=node.semantic_id,
object_hash=object_hash,
task_id=task_id,
session_id=session_id,
parent_version_id=previous.version_id if previous else None,
payload=payload,
)
versions = self._versions_by_lineage.setdefault(node.lineage_id, [])
if not versions or versions[-1].object_hash != object_hash:
versions.append(version)
return versions[-1]
def append_snapshot_versions(
self,
snapshot: SirSnapshot,
*,
task_id: str | None = None,
session_id: str | None = None,
) -> list[SemanticObjectVersion]:
return [
self.append_node_version(node, task_id=task_id, session_id=session_id)
for node in snapshot.nodes
]
def upsert_version(self, version: SemanticObjectVersion) -> SemanticObjectVersion:
versions = self._versions_by_lineage.setdefault(version.lineage_id, [])
if all(existing.version_id != version.version_id for existing in versions):
versions.append(version)
versions.sort(key=lambda item: item.created_at)
return version
def latest(self, lineage_id: str) -> SemanticObjectVersion | None:
versions = self._versions_by_lineage.get(lineage_id, [])
return versions[-1] if versions else None
def find_version(self, version_id: str) -> SemanticObjectVersion | None:
return next((version for version in self.all_versions() if version.version_id == version_id), None)
def history(self, lineage_id: str) -> list[SemanticObjectVersion]:
return list(self._versions_by_lineage.get(lineage_id, []))
def all_versions(self) -> list[SemanticObjectVersion]:
return [
version
for versions in self._versions_by_lineage.values()
for version in versions
]
def diff_versions(
before: SemanticObjectVersion,
after: SemanticObjectVersion,
) -> SemanticObjectDiff:
if before.lineage_id != after.lineage_id:
raise ValueError("Cannot diff versions from different lineage_id values")
entries = _diff_payload("", before.payload, after.payload)
return SemanticObjectDiff(
from_version_id=before.version_id,
to_version_id=after.version_id,
lineage_id=before.lineage_id,
changed=bool(entries),
entries=entries,
)
def classify_version_change(
before: SemanticObjectVersion,
after: SemanticObjectVersion,
) -> SemanticObjectChange:
diff = diff_versions(before, after)
if not diff.changed:
change_kind = "UNCHANGED"
elif _object_parent(before.payload.get("qualified_name")) != _object_parent(after.payload.get("qualified_name")):
change_kind = "MOVE"
elif before.payload.get("name") != after.payload.get("name"):
change_kind = "RENAME"
else:
change_kind = "UPDATE"
return SemanticObjectChange(change_kind=change_kind, diff=diff)
def _object_parent(qualified_name: object) -> str:
if not isinstance(qualified_name, str) or "." not in qualified_name:
return ""
return qualified_name.rsplit(".", 1)[0]
def _diff_payload(path: str, before: object, after: object) -> list[SemanticObjectDiffEntry]:
if isinstance(before, dict) and isinstance(after, dict):
entries: list[SemanticObjectDiffEntry] = []
for key in sorted(set(before) | set(after)):
child_path = f"{path}.{key}" if path else str(key)
if key not in before:
entries.append(SemanticObjectDiffEntry(path=child_path, kind="ADD", after=after[key]))
elif key not in after:
entries.append(SemanticObjectDiffEntry(path=child_path, kind="REMOVE", before=before[key]))
else:
entries.extend(_diff_payload(child_path, before[key], after[key]))
return entries
if before == after:
return []
return [SemanticObjectDiffEntry(path=path or "$", kind="CHANGE", before=before, after=after)]
__all__ = [
"InMemoryObjectVersionStore",
"SemanticObjectDiff",
"SemanticObjectDiffEntry",
"SemanticObjectChange",
"SemanticObjectVersion",
"classify_version_change",
"diff_versions",
]