import pytest from kontextual_engine import ( Actor, ActorType, DuplicateResourceError, InMemoryMemoryGraphRepository, MemoryGraphImportResult, MemoryRuntimeService, OperationContext, ValidationError, ) def test_markitect_memory_graph_import_preserves_contract_identity_and_spans() -> None: imported = MemoryGraphImportResult.from_markitect_contract( _graph_contract(), profile_contract=_profile_contract(), ) second_import = MemoryGraphImportResult.from_markitect_contract(_graph_contract()) assert imported.graph_id == second_import.graph_id assert imported.contract_graph_id == "markitect-memory-decisions" assert imported.profile is not None assert imported.profile.contract_profile_id == "local-agent-memory" assert imported.nodes[0].contract_node_id == "decision.contract-boundary" assert imported.nodes[0].node_id == second_import.nodes[0].node_id assert imported.nodes[0].source_spans[0].path == "workplans/MKTT-WP-0016.md" assert imported.edges[0].source_node_id == imported.nodes[1].node_id assert imported.events[0].package_refs == ("memory:package:example",) def test_in_memory_memory_repository_persists_graph_and_append_only_events() -> None: repo = InMemoryMemoryGraphRepository() imported = MemoryGraphImportResult.from_markitect_contract(_graph_contract()) for node in imported.nodes: repo.save_memory_node(node) repo.save_memory_edge(imported.edges[0]) repo.append_memory_event(imported.events[0]) assert repo.list_memory_nodes(graph_id=imported.graph_id, kind="decision") == [imported.nodes[0]] assert repo.list_memory_edges(source_node_id=imported.nodes[1].node_id) == [imported.edges[0]] assert repo.list_memory_events(graph_id=imported.graph_id, kind="recorded") == [imported.events[0]] with pytest.raises(DuplicateResourceError): repo.append_memory_event(imported.events[0]) def test_memory_runtime_service_imports_contracts_and_reports_audit_context() -> None: repo = InMemoryMemoryGraphRepository() service = MemoryRuntimeService(repo) actor = Actor.create(ActorType.AI_AGENT, actor_id="agent-codex", display_name="Codex") context = OperationContext.create(actor, correlation_id="corr-memory") summary = service.import_markitect_graph( _graph_contract(), profile_contract=_profile_contract(), context=context, ) assert summary.imported_nodes == 2 assert summary.imported_edges == 1 assert summary.appended_events == 1 assert summary.audit_event is not None assert summary.audit_event.actor_id == "agent-codex" assert summary.audit_event.correlation_id == "corr-memory" assert repo.get_memory_profile(summary.profile_id).memory_kinds == ( "reasoning", "knowledge", "package", ) def test_memory_runtime_service_rejects_invalid_edge_contracts() -> None: repo = InMemoryMemoryGraphRepository() service = MemoryRuntimeService(repo) graph = _graph_contract() graph["edges"][0]["target"] = "missing-node" with pytest.raises(ValidationError) as exc: service.import_markitect_graph(graph) assert "unknown node" in str(exc.value) def _profile_contract() -> dict: return { "schema_version": "markitect.memory.profile.v1", "id": "local-agent-memory", "title": "Local Agent Memory", "intent": "Runtime import fixture.", "memory_kinds": ["reasoning", "knowledge", "package"], "stores": { "reasoning": "local-event-log", "knowledge": "local-graph-store", "package": "markitect-context-registry", }, "activation": {"max_items": 6, "max_tokens": 1800}, "policy": {"required_labels": ["public"]}, } def _graph_contract() -> dict: return { "schema_version": "markitect.memory.graph.v1", "id": "markitect-memory-decisions", "title": "Markitect Memory Decisions", "intent": "Preserve memory boundary decisions for runtime import.", "namespace": {"project": "markitect-tool", "task": "MKTT-WP-0016"}, "nodes": [ { "id": "decision.contract-boundary", "kind": "decision", "text": "Markitect compiles memory graph selections into context packages.", "source_spans": [ { "path": "workplans/MKTT-WP-0016.md", "unit_kind": "section", "selector": "tasks[id=P16.5]", "engine": "selector", } ], "metadata": {"title": "Contract boundary decision"}, }, { "id": "constraint.no-runtime-services", "kind": "constraint", "text": "Runtime persistence belongs in kontextual-engine.", "policy": {"labels": ["public"]}, }, ], "edges": [ { "id": "edge.boundary-support", "kind": "supports", "source": "constraint.no-runtime-services", "target": "decision.contract-boundary", } ], "events": [ { "id": "event.initial-contract", "kind": "recorded", "timestamp": "2026-05-15T00:00:00Z", "actor": "agent-codex", "task": "KONT-WP-0017", "package_refs": ["memory:package:example"], "node_updates": [ {"node_id": "decision.contract-boundary", "operation": "import"} ], } ], }