Add profile-driven lifecycle rules

This commit is contained in:
2026-05-18 22:20:14 +02:00
parent 322571c02c
commit 908494b712
12 changed files with 700 additions and 14 deletions

View File

@@ -1,7 +1,24 @@
import json
from datetime import datetime, timezone
from pathlib import Path
from phase_memory.lifecycle import plan_compaction, plan_phase_transition, plan_refresh, plan_retention
from phase_memory.models import LifecycleActionKind, LifecycleState, MemoryNode, MemoryPhase
from phase_memory.contracts import graph_from_markitect
from phase_memory.lifecycle import (
LifecycleRuleConfig,
plan_compaction,
plan_lifecycle_from_profile,
plan_phase_transition,
plan_refresh,
plan_retention,
)
from phase_memory.models import LifecycleActionKind, LifecycleState, MemoryGraph, MemoryNode, MemoryPhase
FIXTURES = Path(__file__).parent / "fixtures"
def _load(name: str):
return json.loads((FIXTURES / name).read_text(encoding="utf-8"))
def test_phase_transition_to_stabilized_requires_review() -> None:
@@ -47,3 +64,61 @@ def test_compaction_and_refresh_are_reviewable_plans() -> None:
assert refresh.action == LifecycleActionKind.REFRESH
assert refresh.requires_review
assert refresh.metadata["proposed_digest"] == "new"
def test_profile_retention_rules_drive_lifecycle_plan_from_fixture() -> None:
now = datetime(2026, 5, 18, tzinfo=timezone.utc)
profile = _load("memory-profile.json")
graph = graph_from_markitect(_load("memory-graph.json")).value
config = LifecycleRuleConfig.from_profile(profile)
actions = plan_lifecycle_from_profile(
graph,
profile,
refresh_digests={"event.restart": "new"},
now=now,
)
by_target_and_action = {(action.target_id, action.action): action for action in actions}
assert config.retention_default.stale_after_days == 7
assert by_target_and_action[("event.restart", LifecycleActionKind.MARK_STALE)].to_state == LifecycleState.STALE
assert by_target_and_action[("event.restart", LifecycleActionKind.REFRESH)].requires_review
def test_profile_transition_rules_promote_matching_nodes() -> None:
now = datetime(2026, 5, 18, tzinfo=timezone.utc)
graph = MemoryGraph(
"graph.rules",
nodes=(
MemoryNode(
"episode.old",
"episode",
"Useful trace",
phase=MemoryPhase.FLUID,
freshness={"updated_at": "2026-05-01T00:00:00+00:00"},
),
),
)
profile = {
"schema_version": "markitect.memory.profile.v1",
"id": "profile.rules",
"metadata": {
"phase_transitions": [
{
"kind": "episode",
"from_phase": "fluid",
"to_phase": "stabilized",
"min_age_days": 7,
"reason": "episode old enough to stabilize",
}
]
},
}
actions = plan_lifecycle_from_profile(graph, profile, now=now)
assert len(actions) == 1
assert actions[0].action == LifecycleActionKind.TRANSITION_PHASE
assert actions[0].target_id == "episode.old"
assert actions[0].requires_review is True
assert actions[0].metadata["to_phase"] == "stabilized"