generated from coulomb/repo-seed
Governed asset registry slice with asset creation, representations, metadata, lifecycle transitions, policy authorization, fail-closed denial, audit events, and version records
This commit is contained in:
130
src/kontextual_engine/adapters/memory/asset_registry.py
Normal file
130
src/kontextual_engine/adapters/memory/asset_registry.py
Normal file
@@ -0,0 +1,130 @@
|
||||
"""In-memory asset registry repository."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Iterable
|
||||
|
||||
from kontextual_engine.core import (
|
||||
Actor,
|
||||
AssetRepresentation,
|
||||
AssetVersion,
|
||||
AuditEvent,
|
||||
KnowledgeAsset,
|
||||
LifecycleState,
|
||||
MetadataRecord,
|
||||
RepresentationKind,
|
||||
)
|
||||
from kontextual_engine.errors import NotFoundError, ValidationError
|
||||
|
||||
|
||||
@dataclass
|
||||
class InMemoryAssetRegistryRepository:
|
||||
actors: dict[str, Actor] = field(default_factory=dict)
|
||||
assets: dict[str, KnowledgeAsset] = field(default_factory=dict)
|
||||
representations: dict[str, AssetRepresentation] = field(default_factory=dict)
|
||||
metadata_records: dict[str, list[MetadataRecord]] = field(default_factory=dict)
|
||||
versions: dict[str, list[AssetVersion]] = field(default_factory=dict)
|
||||
audit_events: dict[str, AuditEvent] = field(default_factory=dict)
|
||||
|
||||
def save_actor(self, actor: Actor) -> Actor:
|
||||
self.actors[actor.id] = actor
|
||||
return actor
|
||||
|
||||
def get_actor(self, actor_id: str) -> Actor:
|
||||
try:
|
||||
return self.actors[actor_id]
|
||||
except KeyError as exc:
|
||||
raise NotFoundError("Actor not found", details={"actor_id": actor_id}) from exc
|
||||
|
||||
def save_asset(self, asset: KnowledgeAsset) -> KnowledgeAsset:
|
||||
self.assets[asset.id] = asset
|
||||
return asset
|
||||
|
||||
def get_asset(self, asset_id: str) -> KnowledgeAsset:
|
||||
try:
|
||||
return self.assets[asset_id]
|
||||
except KeyError as exc:
|
||||
raise NotFoundError("Asset not found", details={"asset_id": asset_id}) from exc
|
||||
|
||||
def list_assets(
|
||||
self,
|
||||
*,
|
||||
lifecycle: LifecycleState | None = None,
|
||||
asset_type: str | None = None,
|
||||
) -> list[KnowledgeAsset]:
|
||||
assets: Iterable[KnowledgeAsset] = self.assets.values()
|
||||
if lifecycle is not None:
|
||||
assets = [asset for asset in assets if asset.lifecycle == lifecycle]
|
||||
if asset_type is not None:
|
||||
assets = [asset for asset in assets if asset.classification.asset_type == asset_type]
|
||||
return sorted(assets, key=lambda asset: (asset.title, asset.id))
|
||||
|
||||
def save_representation(self, representation: AssetRepresentation) -> AssetRepresentation:
|
||||
self.get_asset(representation.asset_id)
|
||||
self.representations[representation.representation_id] = representation
|
||||
return representation
|
||||
|
||||
def get_representation(self, representation_id: str) -> AssetRepresentation:
|
||||
try:
|
||||
return self.representations[representation_id]
|
||||
except KeyError as exc:
|
||||
raise NotFoundError(
|
||||
"Representation not found",
|
||||
details={"representation_id": representation_id},
|
||||
) from exc
|
||||
|
||||
def list_representations(
|
||||
self,
|
||||
*,
|
||||
asset_id: str | None = None,
|
||||
kind: RepresentationKind | None = None,
|
||||
) -> list[AssetRepresentation]:
|
||||
representations: Iterable[AssetRepresentation] = self.representations.values()
|
||||
if asset_id is not None:
|
||||
representations = [item for item in representations if item.asset_id == asset_id]
|
||||
if kind is not None:
|
||||
representations = [item for item in representations if item.kind == kind]
|
||||
return sorted(representations, key=lambda item: (item.asset_id, item.kind.value, item.representation_id))
|
||||
|
||||
def save_metadata_record(self, asset_id: str, record: MetadataRecord) -> MetadataRecord:
|
||||
self.get_asset(asset_id)
|
||||
self.metadata_records.setdefault(asset_id, []).append(record)
|
||||
return record
|
||||
|
||||
def list_metadata_records(self, asset_id: str) -> list[MetadataRecord]:
|
||||
self.get_asset(asset_id)
|
||||
return list(self.metadata_records.get(asset_id, []))
|
||||
|
||||
def save_version(self, version: AssetVersion) -> AssetVersion:
|
||||
self.get_asset(version.asset_id)
|
||||
current = self.versions.setdefault(version.asset_id, [])
|
||||
if any(existing.sequence == version.sequence for existing in current):
|
||||
raise ValidationError(
|
||||
"Version sequence already exists for asset",
|
||||
details={"asset_id": version.asset_id, "sequence": version.sequence},
|
||||
)
|
||||
current.append(version)
|
||||
return version
|
||||
|
||||
def list_versions(self, asset_id: str) -> list[AssetVersion]:
|
||||
self.get_asset(asset_id)
|
||||
return sorted(self.versions.get(asset_id, []), key=lambda version: version.sequence)
|
||||
|
||||
def save_audit_event(self, event: AuditEvent) -> AuditEvent:
|
||||
self.audit_events[event.event_id] = event
|
||||
return event
|
||||
|
||||
def list_audit_events(
|
||||
self,
|
||||
*,
|
||||
target: str | None = None,
|
||||
correlation_id: str | None = None,
|
||||
) -> list[AuditEvent]:
|
||||
events: Iterable[AuditEvent] = self.audit_events.values()
|
||||
if target is not None:
|
||||
events = [event for event in events if event.target == target]
|
||||
if correlation_id is not None:
|
||||
events = [event for event in events if event.correlation_id == correlation_id]
|
||||
return sorted(events, key=lambda event: (event.occurred_at, event.event_id))
|
||||
|
||||
Reference in New Issue
Block a user