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
+35
View File
@@ -0,0 +1,35 @@
from sir.delta import SirDelta
from sir.diagnostics import Diagnostic, DiagnosticSeverity
from sir.edges import SemanticEdge
from sir.enums import EdgeKind, NodeKind
from sir.hashing import compute_snapshot_hash
from sir.lineage import make_lineage_id, make_semantic_id, stable_hash
from sir.nodes import SemanticNode
from sir.references import ReferenceKind, UnresolvedReference
from sir.serialization import snapshot_from_json, snapshot_to_json
from sir.snapshot import SirSnapshot, SnapshotMetadata
from sir.source_ref import SourceRef
from sir.validation import SnapshotValidationError, validate_snapshot
__all__ = [
"Diagnostic",
"DiagnosticSeverity",
"EdgeKind",
"NodeKind",
"ReferenceKind",
"SemanticEdge",
"SemanticNode",
"SirDelta",
"SirSnapshot",
"SnapshotMetadata",
"SnapshotValidationError",
"SourceRef",
"UnresolvedReference",
"compute_snapshot_hash",
"make_lineage_id",
"make_semantic_id",
"snapshot_from_json",
"snapshot_to_json",
"stable_hash",
"validate_snapshot",
]
+15
View File
@@ -0,0 +1,15 @@
from pydantic import BaseModel, Field
from sir.edges import SemanticEdge
from sir.nodes import SemanticNode
class SirDelta(BaseModel):
delta_id: str
snapshot_from: str
snapshot_to: str
added_nodes: list[SemanticNode] = Field(default_factory=list)
updated_nodes: list[SemanticNode] = Field(default_factory=list)
removed_nodes: list[str] = Field(default_factory=list)
added_edges: list[SemanticEdge] = Field(default_factory=list)
removed_edges: list[str] = Field(default_factory=list)
+21
View File
@@ -0,0 +1,21 @@
from enum import Enum
from pydantic import BaseModel, Field
from sir.source_ref import SourceRef
class DiagnosticSeverity(str, Enum):
INFO = "INFO"
WARNING = "WARNING"
ERROR = "ERROR"
class Diagnostic(BaseModel):
diagnostic_id: str
code: str
severity: DiagnosticSeverity
message: str
source_ref: SourceRef | None = None
related_lineages: list[str] = Field(default_factory=list)
attributes: dict = Field(default_factory=dict)
+13
View File
@@ -0,0 +1,13 @@
from pydantic import BaseModel, Field
from sir.enums import EdgeKind
from sir.source_ref import SourceRef
class SemanticEdge(BaseModel):
edge_id: str
kind: EdgeKind
source_lineage: str
target_lineage: str
source_ref: SourceRef | None = None
attributes: dict = Field(default_factory=dict)
+59
View File
@@ -0,0 +1,59 @@
from enum import Enum
class NodeKind(str, Enum):
PROJECT = "PROJECT"
MODULE = "MODULE"
PROCEDURE = "PROCEDURE"
FUNCTION = "FUNCTION"
QUERY = "QUERY"
TABLE = "TABLE"
REGISTER = "REGISTER"
CATALOG = "CATALOG"
DOCUMENT = "DOCUMENT"
CONSTANT = "CONSTANT"
DOCUMENT_JOURNAL = "DOCUMENT_JOURNAL"
ENUM = "ENUM"
REPORT = "REPORT"
DATA_PROCESSOR = "DATA_PROCESSOR"
CHART_OF_CHARACTERISTIC_TYPES = "CHART_OF_CHARACTERISTIC_TYPES"
CHART_OF_ACCOUNTS = "CHART_OF_ACCOUNTS"
CHART_OF_CALCULATION_TYPES = "CHART_OF_CALCULATION_TYPES"
COMMON_MODULE = "COMMON_MODULE"
EXCHANGE_PLAN = "EXCHANGE_PLAN"
EXTERNAL_DATA_SOURCE = "EXTERNAL_DATA_SOURCE"
SCHEDULED_JOB = "SCHEDULED_JOB"
BUSINESS_PROCESS = "BUSINESS_PROCESS"
TASK = "TASK"
SUBSYSTEM = "SUBSYSTEM"
HTTP_SERVICE = "HTTP_SERVICE"
XDTO_PACKAGE = "XDTO_PACKAGE"
EXTENSION = "EXTENSION"
LAYOUT = "LAYOUT"
MOVEMENT = "MOVEMENT"
INTEGRATION_ENDPOINT = "INTEGRATION_ENDPOINT"
FORM = "FORM"
COMMAND = "COMMAND"
ROLE = "ROLE"
ATTRIBUTE = "ATTRIBUTE"
TABULAR_SECTION = "TABULAR_SECTION"
FORM_ELEMENT = "FORM_ELEMENT"
class EdgeKind(str, Enum):
CONTAINS = "CONTAINS"
DECLARES = "DECLARES"
CALLS = "CALLS"
OWNS_QUERY = "OWNS_QUERY"
READS_TABLE = "READS_TABLE"
WRITES = "WRITES"
HAS_FORM = "HAS_FORM"
HAS_COMMAND = "HAS_COMMAND"
HAS_ROLE = "HAS_ROLE"
HAS_ATTRIBUTE = "HAS_ATTRIBUTE"
HAS_TABULAR_SECTION = "HAS_TABULAR_SECTION"
HAS_ELEMENT = "HAS_ELEMENT"
GRANTS_ACCESS = "GRANTS_ACCESS"
RUNS = "RUNS"
USES_INTEGRATION = "USES_INTEGRATION"
HANDLES = "HANDLES"
+13
View File
@@ -0,0 +1,13 @@
import hashlib
import orjson
from sir.snapshot import SirSnapshot
def compute_snapshot_hash(snapshot: SirSnapshot) -> str:
payload = snapshot.model_dump(mode="json")
payload["snapshot_hash"] = None
payload["created_at"] = None
raw = orjson.dumps(payload, option=orjson.OPT_SORT_KEYS)
return hashlib.sha256(raw).hexdigest()
+13
View File
@@ -0,0 +1,13 @@
import hashlib
def stable_hash(value: str) -> str:
return hashlib.sha1(value.encode("utf-8")).hexdigest()[:16]
def make_lineage_id(kind: str, stable_key: str) -> str:
return f"lineage.{kind.lower()}.{stable_hash(stable_key)}"
def make_semantic_id(kind: str, qualified_name: str) -> str:
return f"{kind.lower()}.{stable_hash(qualified_name)}"
+14
View File
@@ -0,0 +1,14 @@
from pydantic import BaseModel, Field
from sir.enums import NodeKind
from sir.source_ref import SourceRef
class SemanticNode(BaseModel):
semantic_id: str
lineage_id: str
kind: NodeKind
name: str
qualified_name: str
source_ref: SourceRef
attributes: dict = Field(default_factory=dict)
+22
View File
@@ -0,0 +1,22 @@
from enum import Enum
from pydantic import BaseModel, Field
from sir.source_ref import SourceRef
class ReferenceKind(str, Enum):
CALL = "CALL"
TABLE = "TABLE"
ATTRIBUTE = "ATTRIBUTE"
FORM_ELEMENT = "FORM_ELEMENT"
COMMAND = "COMMAND"
class UnresolvedReference(BaseModel):
reference_id: str
kind: ReferenceKind
source_lineage: str
target_name: str
source_ref: SourceRef
attributes: dict = Field(default_factory=dict)
+11
View File
@@ -0,0 +1,11 @@
import orjson
from sir.snapshot import SirSnapshot
def snapshot_to_json(snapshot: SirSnapshot) -> bytes:
return orjson.dumps(snapshot.model_dump(mode="json"), option=orjson.OPT_INDENT_2)
def snapshot_from_json(data: bytes) -> SirSnapshot:
return SirSnapshot.model_validate_json(data)
+32
View File
@@ -0,0 +1,32 @@
from datetime import datetime, timezone
from pydantic import BaseModel, Field
from sir.diagnostics import Diagnostic
from sir.edges import SemanticEdge
from sir.nodes import SemanticNode
from sir.references import UnresolvedReference
class SnapshotMetadata(BaseModel):
platform_version: str | None = None
compatibility_mode: str | None = None
source_kind: str | None = None
source_root: str | None = None
created_by: str | None = None
task_id: str | None = None
session_id: str | None = None
class SirSnapshot(BaseModel):
sir_schema_version: str = "0.1"
snapshot_id: str
project_id: str
revision: str | None = None
snapshot_hash: str | None = None
metadata: SnapshotMetadata = Field(default_factory=SnapshotMetadata)
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
nodes: list[SemanticNode] = Field(default_factory=list)
edges: list[SemanticEdge] = Field(default_factory=list)
diagnostics: list[Diagnostic] = Field(default_factory=list)
unresolved_references: list[UnresolvedReference] = Field(default_factory=list)
+10
View File
@@ -0,0 +1,10 @@
from pydantic import BaseModel
class SourceRef(BaseModel):
source_path: str
line_start: int | None = None
line_end: int | None = None
column_start: int | None = None
column_end: int | None = None
source_hash: str | None = None
+30
View File
@@ -0,0 +1,30 @@
from sir.snapshot import SirSnapshot
class SnapshotValidationError(Exception):
"""Raised when a SIR snapshot violates graph consistency rules."""
def validate_snapshot(snapshot: SirSnapshot) -> None:
semantic_ids = [node.semantic_id for node in snapshot.nodes]
lineage_ids = [node.lineage_id for node in snapshot.nodes]
if len(semantic_ids) != len(set(semantic_ids)):
raise SnapshotValidationError("Duplicate semantic_id detected")
if len(lineage_ids) != len(set(lineage_ids)):
raise SnapshotValidationError("Duplicate lineage_id detected")
known_lineages = set(lineage_ids)
for edge in snapshot.edges:
if edge.source_lineage not in known_lineages:
raise SnapshotValidationError(f"Dangling edge source: {edge.source_lineage}")
if edge.target_lineage not in known_lineages:
raise SnapshotValidationError(f"Dangling edge target: {edge.target_lineage}")
for reference in snapshot.unresolved_references:
if reference.source_lineage not in known_lineages:
raise SnapshotValidationError(
f"Unresolved reference with unknown source: {reference.source_lineage}"
)