"""Layer 3 — Geometry Authority Kernel: implicit geometry, constraint solvers, feature lineage.""" from abc import ABC, abstractmethod from typing import Any from pydantic import BaseModel, Field class FeatureLineageEntry(BaseModel): """Single feature lineage entry: feature -> intent node, physics justification, process eligibility.""" feature_id: str = Field(...) intent_node_id: str = Field(...) physics_justification_ref: str | None = Field(default=None) process_eligible: bool = Field(default=False) class GeometryAuthorityInterface(ABC): """ Interface for implicit geometry, constraint solvers, feature lineage. Every geometric feature must map to intent node, physics justification, process eligibility. Orphan geometry is prohibited. """ @abstractmethod def add_feature( self, feature_id: str, intent_node_id: str, physics_justification_ref: str | None = None, process_eligible: bool = False, payload: dict[str, Any] | None = None, ) -> FeatureLineageEntry: """Register a feature with lineage; orphan (no intent) prohibited.""" ... @abstractmethod def get_lineage(self, feature_id: str) -> FeatureLineageEntry | None: """Return lineage for feature or None.""" ... @abstractmethod def validate_no_orphans(self) -> list[str]: """Return list of feature ids with no valid lineage (orphans); must be empty for MPC.""" ... class InMemoryGeometryKernel(GeometryAuthorityInterface): """ In-memory lineage model; no concrete CAD kernel. Only tracks features registered via add_feature; validate_no_orphans returns [] since every stored feature has lineage. For a kernel that tracks all feature ids separately, override validate_no_orphans to return ids not in lineage. """ def __init__(self) -> None: self._lineage: dict[str, FeatureLineageEntry] = {} def add_feature( self, feature_id: str, intent_node_id: str, physics_justification_ref: str | None = None, process_eligible: bool = False, payload: dict[str, Any] | None = None, ) -> FeatureLineageEntry: entry = FeatureLineageEntry( feature_id=feature_id, intent_node_id=intent_node_id, physics_justification_ref=physics_justification_ref, process_eligible=process_eligible, ) self._lineage[feature_id] = entry return entry def get_lineage(self, feature_id: str) -> FeatureLineageEntry | None: return self._lineage.get(feature_id) def validate_no_orphans(self) -> list[str]: """Return []; this stub only tracks registered features, so none are orphans.""" return []