integrate ganjihong engine refactor
This commit is contained in:
@@ -32,6 +32,66 @@ def _mappings(value: Any):
|
||||
yield from _mappings(child)
|
||||
|
||||
|
||||
def _contract_selectors(feature: dict[str, Any], contract: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
"""Return the selectors at the operation contract's declared slot."""
|
||||
slot = str(contract.get("selector_slot") or "")
|
||||
if slot == "feature.selectors":
|
||||
values = feature.get("selectors") or []
|
||||
elif slot.startswith("params.") and slot.count(".") == 1:
|
||||
value = (feature.get("params") or {}).get(slot.removeprefix("params."))
|
||||
values = value if isinstance(value, list) else [value]
|
||||
else:
|
||||
values = []
|
||||
return [value for value in values if isinstance(value, dict)]
|
||||
|
||||
|
||||
def _validate_selector_intent(selector: dict[str, Any], feature_id: str, index: int) -> None:
|
||||
"""Enforce the provenance boundary before the runtime can bind a selector."""
|
||||
intent = selector.get("selector_intent")
|
||||
if intent is None:
|
||||
if selector.get("selector_intent_version") is not None:
|
||||
raise ValueError(f"Feature {feature_id} selector {index} declares an intent version without selector_intent")
|
||||
return
|
||||
if selector.get("selector_intent_version") not in {None, "1.0"}:
|
||||
raise ValueError(f"Feature {feature_id} selector {index} has an unsupported selector intent version")
|
||||
if not isinstance(intent, dict) or intent.get("version") != "1.0":
|
||||
raise ValueError(f"Feature {feature_id} selector {index} has an unsupported selector intent")
|
||||
if intent.get("kind") not in {None, selector.get("kind")}:
|
||||
raise ValueError(f"Feature {feature_id} selector {index} intent kind differs from selector kind")
|
||||
family = intent.get("query_family")
|
||||
derived = {"CAP_FACE", "CAP_EDGE", "SWEPT_FACE", "SWEPT_EDGE", "OFFSET_FACE", "INTERSECT", "COPY"}
|
||||
if family in derived and not selector.get("owner_feature_id"):
|
||||
raise ValueError(f"Feature {feature_id} selector {index} derived intent requires owner_feature_id")
|
||||
policy = intent.get("derivation_policy") or {}
|
||||
allowed = policy.get("allowed") or []
|
||||
if not allowed or any(value not in {"continuation", "fragment", "merge", "intersection", "boundary", "replacement"} for value in allowed):
|
||||
raise ValueError(f"Feature {feature_id} selector {index} has an invalid lineage derivation policy")
|
||||
if policy.get("multiplicity") not in {"one", "all_fragments", "source_qualified", "none"}:
|
||||
raise ValueError(f"Feature {feature_id} selector {index} has an invalid lineage multiplicity")
|
||||
if policy.get("multiplicity") == "all_fragments" and "fragment" not in allowed:
|
||||
raise ValueError(f"Feature {feature_id} selector {index} all_fragments policy requires fragment lineage")
|
||||
if family in derived and intent.get("evidence") == "geometry_hint":
|
||||
raise ValueError(f"Feature {feature_id} selector {index} cannot use geometry_hint for FeatureScript provenance")
|
||||
if selector.get("owner_match_required") and intent.get("evidence") == "geometry_hint":
|
||||
raise ValueError(f"Feature {feature_id} selector {index} owner match cannot use geometry fallback")
|
||||
source_query = intent.get("source_query") or {}
|
||||
version = source_query.get("featurescript_version") if isinstance(source_query, dict) else None
|
||||
if not isinstance(version, str) or not re.fullmatch(r"[0-9]+(?:\.[0-9]+)*", version):
|
||||
raise ValueError(f"Feature {feature_id} selector {index} has an unknown FeatureScript query version")
|
||||
if intent.get("output_role") is not None and intent.get("output_role") != selector.get("output_role"):
|
||||
raise ValueError(f"Feature {feature_id} selector {index} intent output role differs from selector output role")
|
||||
forbidden = {"runtime_id", "record_id", "topology_record_id", "task_id", "revision_id"}
|
||||
stack = [intent]
|
||||
while stack:
|
||||
value = stack.pop()
|
||||
if isinstance(value, dict):
|
||||
if forbidden.intersection(value):
|
||||
raise ValueError(f"Feature {feature_id} selector {index} intent contains a runtime identifier")
|
||||
stack.extend(value.values())
|
||||
elif isinstance(value, list):
|
||||
stack.extend(value)
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def _schema() -> dict[str, Any]:
|
||||
path = Path(__file__).with_name("cdsl_schema.json")
|
||||
@@ -69,7 +129,7 @@ def validate_semantic_cdsl(cdsl: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
if not isinstance(cdsl, dict):
|
||||
raise ValueError("CDSL must be a JSON object")
|
||||
if cdsl.get("schema") != "cad.cdsl.llm.v1":
|
||||
if cdsl.get("schema") not in {"cad.cdsl.llm.v1", "cad.runtime.v1"}:
|
||||
raise ValueError("Unsupported CDSL schema")
|
||||
schema_error = _schema_error(cdsl)
|
||||
if schema_error:
|
||||
@@ -124,15 +184,21 @@ def validate_semantic_cdsl(cdsl: dict[str, Any]) -> dict[str, Any]:
|
||||
if feature.get("execution_status") == "deferred":
|
||||
deferred.append(fid)
|
||||
contract = contracts.get(str(feature.get("atomic_id") or "")) or {}
|
||||
feature_selectors = feature.get("selectors") or []
|
||||
feature_selectors = _contract_selectors(feature, contract)
|
||||
output_role_selector_ids = {id(selector) for selector in feature_selectors if isinstance(selector, dict)}
|
||||
selector_intent_ids = {
|
||||
id(selector.get("selector_intent"))
|
||||
for selector in feature_selectors
|
||||
if isinstance(selector, dict) and isinstance(selector.get("selector_intent"), dict)
|
||||
}
|
||||
for index, selector in enumerate(feature_selectors):
|
||||
_validate_selector_intent(selector, fid, index)
|
||||
owner = selector.get("owner_feature_id")
|
||||
binding_owner = selector.get("binding_feature_id")
|
||||
if owner is not None and owner not in feature_ids and binding_owner not in feature_ids:
|
||||
raise ValueError(f"Feature {fid} selector {index} has a forward or missing owner_feature_id")
|
||||
if selector.get("output_role") is not None:
|
||||
if contract.get("selector_slot") != "feature.selectors" or contract.get("selector_token_kind") != "face":
|
||||
if not contract.get("selector_slot") or contract.get("selector_token_kind") != "face":
|
||||
raise ValueError(f"Feature {fid} selector {index} cannot consume a feature output role")
|
||||
if selector.get("kind") != "face" or not owner or owner not in feature_ids:
|
||||
raise ValueError(f"Feature {fid} selector {index} output role requires a preceding face owner_feature_id")
|
||||
@@ -174,8 +240,13 @@ def validate_semantic_cdsl(cdsl: dict[str, Any]) -> dict[str, Any]:
|
||||
selector.get("output_role") is not None
|
||||
and selector.get("kind") is not None
|
||||
and id(selector) not in output_role_selector_ids
|
||||
and id(selector) not in selector_intent_ids
|
||||
):
|
||||
raise ValueError(f"Feature {fid} output role selectors are only supported in feature.selectors")
|
||||
if contract.get("selector_slot") == "feature.selectors":
|
||||
raise ValueError(
|
||||
f"Feature {fid} output role selectors are only supported in feature.selectors"
|
||||
)
|
||||
raise ValueError(f"Feature {fid} output role selector is outside its operation contract slot")
|
||||
if feature.get("atomic_id") == "shell":
|
||||
target_feature_id = (feature.get("params") or {}).get("target_feature_id")
|
||||
if target_feature_id is not None and target_feature_id not in feature_ids:
|
||||
|
||||
Reference in New Issue
Block a user