Files
cleveragents-core/benchmarks/temporal_data_model_bench.py
hamza.khyari d5f7f15215
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / build (pull_request) Successful in 14s
CI / quality (pull_request) Successful in 20s
CI / security (pull_request) Successful in 34s
CI / typecheck (pull_request) Successful in 39s
CI / unit_tests (pull_request) Successful in 2m50s
CI / integration_tests (pull_request) Successful in 3m22s
CI / docker (pull_request) Successful in 40s
CI / coverage (pull_request) Successful in 5m49s
CI / benchmark-regression (pull_request) Successful in 35m15s
feat(acms): implement Temporal Data Model (Revision-Aware RDF) with 3 storage tiers
Temporal metadata fields (validFrom, validUntil, isCurrent, isRevisionOf)
on UKO InformationUnit nodes enable revision chain tracking: when code
changes, old nodes are marked historical and new revision nodes are
created with back-links. Three storage tiers (hot/warm/cold) filter
nodes by temporal scope (current/recent/all) with configurable retention
(warm_retention_hours default 24h, cold_retention_days default 90d).

Includes TemporalMetadata, TemporalNode, RevisionChain, TierQueryResult,
TierRetentionConfig frozen domain models, TemporalBackend protocol,
InMemoryTemporalBackend stub, TemporalService with structlog and DI,
BackendSet.temporal typing upgrade from object|None to TemporalBackend|None.
67 Behave scenarios, 8 Robot Framework tests, ASV benchmarks, and
reference documentation.

ISSUES CLOSED: #577
2026-03-11 01:36:06 +00:00

203 lines
6.2 KiB
Python

"""ASV benchmarks for Temporal Data Model (Revision-Aware RDF).
Measures the performance of:
- TemporalMetadata / TemporalNode / RevisionChain model creation
- InMemoryTemporalBackend revision operations
- Tier-aware temporal queries
- Revision chain traversal
"""
from __future__ import annotations
import importlib
import sys
from datetime import UTC, datetime, timedelta
from pathlib import Path
# Ensure the local *source* tree is importable even when ASV has an
# older build of the package installed.
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
# Force-reload so ASV picks up the source tree version.
import cleveragents # noqa: E402
importlib.reload(cleveragents)
from cleveragents.domain.models.acms.temporal import ( # noqa: E402
RevisionChain,
TemporalMetadata,
TemporalNode,
TierRetentionConfig,
)
from cleveragents.domain.models.acms.temporal_stubs import ( # noqa: E402
InMemoryTemporalBackend,
)
from cleveragents.domain.models.acms.tiers import ContextTier # noqa: E402
from cleveragents.domain.models.core.project import ( # noqa: E402
TemporalScope,
)
_NOW = datetime.now(tz=UTC)
# ---------------------------------------------------------------------------
# Model creation benchmarks
# ---------------------------------------------------------------------------
class TemporalModelSuite:
"""Benchmark temporal domain model creation overhead."""
timeout = 60
def time_create_temporal_metadata(self) -> None:
TemporalMetadata(valid_from=_NOW)
def time_create_temporal_metadata_full(self) -> None:
TemporalMetadata(
valid_from=_NOW,
valid_until=_NOW + timedelta(days=1),
is_current=False,
is_revision_of="uko-py:class/Foo_v1",
)
def time_create_temporal_node(self) -> None:
TemporalNode(
node_uri="uko-py:class/Auth_v1",
source_resource="RES001",
source_path="src/auth.py",
temporal=TemporalMetadata(valid_from=_NOW),
)
def time_create_revision_chain(self) -> None:
RevisionChain(
current_uri="uko-py:class/Auth_v3",
predecessors=(
"uko-py:class/Auth_v1",
"uko-py:class/Auth_v2",
),
)
def time_create_tier_retention_config(self) -> None:
TierRetentionConfig()
# ---------------------------------------------------------------------------
# Backend operation benchmarks
# ---------------------------------------------------------------------------
class TemporalBackendSuite:
"""Benchmark InMemoryTemporalBackend operations."""
timeout = 60
def setup(self) -> None:
"""Create a backend with 10 revision chains of 5 versions each."""
self.backend = InMemoryTemporalBackend()
self.retention = TierRetentionConfig()
for chain_idx in range(10):
base = f"uko-py:class/Chain{chain_idx}"
prev_uri: str | None = None
for ver in range(1, 6):
uri = f"{base}_v{ver}"
node = TemporalNode(
node_uri=uri,
source_resource=f"RES{chain_idx:03d}",
source_path=f"src/chain{chain_idx}.py",
temporal=TemporalMetadata(
valid_from=_NOW - timedelta(days=10 - ver),
is_current=(ver == 5),
is_revision_of=prev_uri,
valid_until=(
_NOW - timedelta(days=10 - ver - 1) if ver < 5 else None
),
),
)
self.backend.store_node(node)
prev_uri = uri
def time_get_current(self) -> None:
self.backend.get_current("uko-py:class/Chain5")
def time_get_history_all(self) -> None:
self.backend.get_history(
"uko-py:class/Chain3",
TemporalScope.ALL,
)
def time_get_history_current(self) -> None:
self.backend.get_history(
"uko-py:class/Chain3",
TemporalScope.CURRENT,
)
def time_get_revision_chain(self) -> None:
self.backend.get_revision_chain("uko-py:class/Chain3_v5")
def time_query_hot_tier(self) -> None:
self.backend.query_by_tier(
ContextTier.HOT,
TemporalScope.CURRENT,
self.retention,
)
def time_query_cold_tier(self) -> None:
self.backend.query_by_tier(
ContextTier.COLD,
TemporalScope.ALL,
self.retention,
)
def time_create_revision(self) -> None:
"""Benchmark a single revision creation (resets after)."""
# Store a temporary node to revise
tmp = TemporalNode(
node_uri="uko-py:class/Tmp_v1",
source_resource="RES999",
source_path="src/tmp.py",
temporal=TemporalMetadata(
valid_from=_NOW - timedelta(days=1),
is_current=True,
),
)
self.backend.store_node(tmp)
new = TemporalNode(
node_uri="uko-py:class/Tmp_v2",
source_resource="RES999",
source_path="src/tmp.py",
temporal=TemporalMetadata(
valid_from=_NOW,
is_current=True,
is_revision_of="uko-py:class/Tmp_v1",
),
)
self.backend.create_revision(
"uko-py:class/Tmp_v1",
new,
_NOW,
)
# Clean up for next iteration
del self.backend._nodes["uko-py:class/Tmp_v1"]
del self.backend._nodes["uko-py:class/Tmp_v2"]
def time_mark_historical(self) -> None:
"""Benchmark marking a node historical (resets after)."""
tmp = TemporalNode(
node_uri="uko-py:class/MarkTmp_v1",
source_resource="RES999",
source_path="src/tmp.py",
temporal=TemporalMetadata(
valid_from=_NOW,
is_current=True,
),
)
self.backend.store_node(tmp)
self.backend.mark_historical("uko-py:class/MarkTmp_v1", _NOW)
del self.backend._nodes["uko-py:class/MarkTmp_v1"]