"""Markitect package bridge helpers.""" from __future__ import annotations from typing import Any, Protocol from .contracts import ContractIngressResult, graph_from_markitect, profile_from_markitect, selection_from_markitect from .models import Diagnostic from .utils import stable_digest MARKITECT_PACKAGE_REQUEST_SCHEMA = "phase_memory.markitect.package_request.v1" MARKITECT_PACKAGE_RESPONSE_SCHEMA = "phase_memory.markitect.package_response.v1" class MarkitectValidator(Protocol): def validate_profile(self, data: dict[str, Any]) -> ContractIngressResult: ... def validate_graph(self, data: dict[str, Any]) -> ContractIngressResult: ... def validate_selection(self, data: dict[str, Any]) -> ContractIngressResult: ... class LocalMarkitectValidator: """Dependency-light validation boundary using local ingress diagnostics.""" def validate_profile(self, data: dict[str, Any]) -> ContractIngressResult: return profile_from_markitect(data) def validate_graph(self, data: dict[str, Any]) -> ContractIngressResult: return graph_from_markitect(data) def validate_selection(self, data: dict[str, Any]) -> ContractIngressResult: return selection_from_markitect(data) class OptionalMarkitectValidator: """Adapter shell for optional Markitect-owned validation.""" def __init__(self, delegate: Any | None = None) -> None: self.delegate = delegate self.local = LocalMarkitectValidator() def validate_profile(self, data: dict[str, Any]) -> ContractIngressResult: if self.delegate and hasattr(self.delegate, "validate_memory_profile"): return self.delegate.validate_memory_profile(data) return self.local.validate_profile(data) def validate_graph(self, data: dict[str, Any]) -> ContractIngressResult: if self.delegate and hasattr(self.delegate, "validate_memory_graph"): return self.delegate.validate_memory_graph(data) return self.local.validate_graph(data) def validate_selection(self, data: dict[str, Any]) -> ContractIngressResult: if self.delegate and hasattr(self.delegate, "validate_memory_selection"): return self.delegate.validate_memory_selection(data) return self.local.validate_selection(data) def package_request_from_selection( selection: dict[str, Any], *, compiler: str, diagnostics: tuple[Diagnostic, ...] = (), ) -> dict[str, Any]: metadata = dict(selection.get("metadata") or {}) request_id = f"markitect-package-request:{stable_digest([selection, compiler])}" return { "schema_version": MARKITECT_PACKAGE_REQUEST_SCHEMA, "id": request_id, "selection_id": selection.get("id"), "graph_id": selection.get("graph"), "profile_id": selection.get("profile"), "selected_nodes": list(selection.get("nodes", ())), "selected_events": list(selection.get("events", ())), "budget": { "max_items": metadata.get("max_items"), "max_tokens": metadata.get("max_tokens"), "token_estimate": metadata.get("token_estimate"), }, "policy": metadata.get("policy", {}), "provenance": { "selected_items": metadata.get("selected_items", {}), "planned_by": metadata.get("planned_by"), }, "compiler": compiler, "compiler_diagnostics": [diagnostic.to_dict() for diagnostic in diagnostics], "selection": dict(selection), "dry_run": True, } def package_response_envelope(response: dict[str, Any], *, request_id: str) -> dict[str, Any]: return { "schema_version": MARKITECT_PACKAGE_RESPONSE_SCHEMA, "request_id": request_id, "package_ref": response.get("package_id") or response.get("package_ref") or "", "compiler_diagnostics": list(response.get("diagnostics", ())), "response": dict(response), }