feat(selector): 增加离线候选遍历与严格回放验证 Demo
- 新增 selector_candidate_demo,移除 provenance intent 后枚举候选 selector - 对候选分支执行有界重建与严格 STEP 比较 - 仅在候选遍历完整且唯一 strict 通过时生成 selector 映射记录 - 增加 selector 候选搜索、预算限制和记录生成的测试 - 保持生产 selector resolver 不受 Demo 逻辑影响 - 更新 CADFS 能力台账,记录 IMPRINT 派生 profile 的 lineage selector 缺口
This commit is contained in:
@@ -20,6 +20,7 @@ working.
|
||||
from __future__ import annotations
|
||||
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
@@ -27,6 +28,7 @@ from . import executors # noqa: F401 (importing performs executor registration
|
||||
from .capabilities import CapabilityAnalyzer, pattern_transform_blocker, sketch_ids_required_by_contract
|
||||
# Historical private name still imported by the test suite.
|
||||
from .executors.primitives import _execute_box # noqa: F401
|
||||
from .executors.common import _selector_edges # noqa: F401
|
||||
from .extents import (
|
||||
_extent_reference,
|
||||
_extent_vectors,
|
||||
@@ -73,6 +75,9 @@ from .topology import (
|
||||
SelectorResolution, TopologyDelta, TopologyDeltaRelation, TopologyRecord, TopologyRegistry,
|
||||
)
|
||||
|
||||
# Historical private imports used by integration tests and local diagnostics.
|
||||
_execute_node = execute_node
|
||||
|
||||
__all__ = [
|
||||
"ALL_ATOMIC_IDS",
|
||||
"EXECUTORS",
|
||||
@@ -85,7 +90,10 @@ __all__ = [
|
||||
"GeometryAdapter",
|
||||
"RuntimeDiagnostic",
|
||||
"RuntimeExecutionError",
|
||||
"IncrementalCdslExecution",
|
||||
"analyze_cdsl",
|
||||
"prepare_cdsl_execution",
|
||||
"finalize_cdsl_execution",
|
||||
"execute_node",
|
||||
"rebuild_cdsl",
|
||||
]
|
||||
@@ -101,8 +109,81 @@ def analyze_cdsl(cdsl: dict[str, Any]):
|
||||
return analyzer.analyze(resolved, sketch_errors=sketch_errors)
|
||||
|
||||
|
||||
def rebuild_cdsl(cdsl: dict[str, Any], out_step: Path, *, strict: bool = True) -> dict[str, Any]:
|
||||
"""Rebuild CDSL through session-scoped atomic executors only."""
|
||||
def _preflight_error(analysis: Any) -> ValueError | None:
|
||||
if analysis.runtime_eligible:
|
||||
return None
|
||||
first = next((result for result in analysis.feature_results if not result.executable), None)
|
||||
if first is None:
|
||||
return ValueError(analysis.document_blockers[0].code)
|
||||
if any(blocker.code == "unknown_atomic" for blocker in first.blockers):
|
||||
return ValueError(f"unsupported atomic_id: {first.atomic_id}")
|
||||
detail = "; ".join(blocker.code for blocker in first.blockers)
|
||||
return ValueError(f"Feature {first.feature_id} is not runtime eligible: {detail}")
|
||||
|
||||
|
||||
def _execution_diagnostic(
|
||||
error: Exception,
|
||||
node: FeaturePlanNode,
|
||||
session: ExecutionSession,
|
||||
) -> RuntimeDiagnostic:
|
||||
failed_resolution = next(
|
||||
(item for item in reversed(session.selector_resolutions) if item["status"] != "resolved"), None,
|
||||
)
|
||||
if isinstance(error, FeatureExecutionError):
|
||||
return RuntimeDiagnostic(error.code, str(error), feature_id=node.feature_id, detail=error.detail)
|
||||
if failed_resolution and failed_resolution.get("diagnostic"):
|
||||
diagnostic = failed_resolution["diagnostic"]
|
||||
return RuntimeDiagnostic(
|
||||
diagnostic["code"], diagnostic["message"], feature_id=node.feature_id,
|
||||
detail=diagnostic.get("detail") or {},
|
||||
)
|
||||
return RuntimeDiagnostic("execution_failed", str(error), feature_id=node.feature_id)
|
||||
|
||||
|
||||
@dataclass
|
||||
class IncrementalCdslExecution:
|
||||
"""One prepared CDSL replay with feature-at-a-time execution.
|
||||
|
||||
CADFS selector binding consumes this object before each feature executes.
|
||||
It therefore observes the exact session topology snapshots generated by
|
||||
the one real kernel replay rather than rebuilding a growing prefix for
|
||||
every selector. The generic runtime also uses it through ``rebuild_cdsl``.
|
||||
"""
|
||||
|
||||
resolved_cdsl: dict[str, Any]
|
||||
analysis: Any
|
||||
session: ExecutionSession
|
||||
diagnostics: list[RuntimeDiagnostic] = field(default_factory=list)
|
||||
next_index: int = 0
|
||||
|
||||
def execute_next(self, *, strict: bool = True) -> FeatureResult | None:
|
||||
if self.next_index >= len(self.analysis.plan):
|
||||
raise ValueError("CDSL execution plan is already complete")
|
||||
node = self.analysis.plan[self.next_index]
|
||||
preflight = self.analysis.feature_results[self.next_index]
|
||||
self.next_index += 1
|
||||
if not preflight.executable:
|
||||
self.diagnostics.extend(preflight.blockers)
|
||||
if strict:
|
||||
detail = "; ".join(blocker.code for blocker in preflight.blockers)
|
||||
raise ValueError(f"Feature {node.feature_id} is not runtime eligible: {detail}")
|
||||
return None
|
||||
try:
|
||||
return execute_node(node, self.session)
|
||||
except Exception as error:
|
||||
diagnostic = _execution_diagnostic(error, node, self.session)
|
||||
self.diagnostics.append(diagnostic)
|
||||
if strict:
|
||||
raise RuntimeExecutionError(diagnostic, list(self.session.selector_resolutions)) from error
|
||||
return None
|
||||
|
||||
def execute_all(self, *, strict: bool = True) -> None:
|
||||
while self.next_index < len(self.analysis.plan):
|
||||
self.execute_next(strict=strict)
|
||||
|
||||
|
||||
def prepare_cdsl_execution(cdsl: dict[str, Any]) -> IncrementalCdslExecution:
|
||||
"""Resolve CDSL once and return a reusable sequential execution session."""
|
||||
sketch_errors: dict[str, str] = {}
|
||||
resolved = resolve_required_sketches(
|
||||
deepcopy(cdsl), sketch_ids_required_by_contract(cdsl), errors=sketch_errors,
|
||||
@@ -110,45 +191,16 @@ def rebuild_cdsl(cdsl: dict[str, Any], out_step: Path, *, strict: bool = True) -
|
||||
analysis = CapabilityAnalyzer(atomic_ids=EXECUTORS, profile_types=CORE_SHAPE_GENERATORS).analyze(
|
||||
resolved, sketch_errors=sketch_errors,
|
||||
)
|
||||
if strict and not analysis.runtime_eligible:
|
||||
first = next((result for result in analysis.feature_results if not result.executable), None)
|
||||
if first is None:
|
||||
raise ValueError(analysis.document_blockers[0].code)
|
||||
if any(blocker.code == "unknown_atomic" for blocker in first.blockers):
|
||||
raise ValueError(f"unsupported atomic_id: {first.atomic_id}")
|
||||
detail = "; ".join(blocker.code for blocker in first.blockers)
|
||||
raise ValueError(f"Feature {first.feature_id} is not runtime eligible: {detail}")
|
||||
session = ExecutionSession(
|
||||
sketches={str(sketch.get("id")): sketch for sketch in (resolved.get("geometry") or {}).get("sketches") or []},
|
||||
nodes={node.feature_id: node for node in analysis.plan},
|
||||
)
|
||||
diagnostics: list[RuntimeDiagnostic] = []
|
||||
for node, preflight in zip(analysis.plan, analysis.feature_results):
|
||||
if not preflight.executable:
|
||||
diagnostics.extend(preflight.blockers)
|
||||
if strict:
|
||||
break
|
||||
continue
|
||||
try:
|
||||
execute_node(node, session)
|
||||
except Exception as error:
|
||||
failed_resolution = next(
|
||||
(item for item in reversed(session.selector_resolutions) if item["status"] != "resolved"), None,
|
||||
)
|
||||
diagnostic = (
|
||||
RuntimeDiagnostic(error.code, str(error), feature_id=node.feature_id, detail=error.detail)
|
||||
if isinstance(error, FeatureExecutionError)
|
||||
else
|
||||
RuntimeDiagnostic(
|
||||
failed_resolution["diagnostic"]["code"], failed_resolution["diagnostic"]["message"],
|
||||
feature_id=node.feature_id, detail=failed_resolution["diagnostic"].get("detail") or {},
|
||||
)
|
||||
if failed_resolution and failed_resolution.get("diagnostic")
|
||||
else RuntimeDiagnostic("execution_failed", str(error), feature_id=node.feature_id)
|
||||
)
|
||||
diagnostics.append(diagnostic)
|
||||
if strict:
|
||||
raise RuntimeExecutionError(diagnostic, list(session.selector_resolutions)) from error
|
||||
return IncrementalCdslExecution(resolved, analysis, session)
|
||||
|
||||
|
||||
def finalize_cdsl_execution(execution: IncrementalCdslExecution, out_step: Path) -> dict[str, Any]:
|
||||
"""Export the current executable checkpoint from an incremental replay."""
|
||||
session = execution.session
|
||||
output = session.body
|
||||
surface_geometry: dict[str, Any] | None = None
|
||||
if output is None:
|
||||
@@ -177,8 +229,19 @@ def rebuild_cdsl(cdsl: dict[str, Any], out_step: Path, *, strict: bool = True) -
|
||||
"surface_face_count": int(surface_geometry["face_count"]) if surface_geometry is not None else 0,
|
||||
"surface_area_mm2": float(surface_geometry["area_mm2"]) if surface_geometry is not None else 0.0,
|
||||
"feature_results": [result.as_dict() for result in session.results.values()],
|
||||
"runtime_diagnostics": [diagnostic.as_dict() for diagnostic in diagnostics],
|
||||
"runtime_diagnostics": [diagnostic.as_dict() for diagnostic in execution.diagnostics],
|
||||
"topology_records": [record.public_dict() for record in session.topology.records()],
|
||||
"topology_deltas": list(session.topology.topology_deltas()),
|
||||
"selector_resolution": session.selector_resolutions,
|
||||
}
|
||||
|
||||
|
||||
def rebuild_cdsl(cdsl: dict[str, Any], out_step: Path, *, strict: bool = True) -> dict[str, Any]:
|
||||
"""Rebuild CDSL through session-scoped atomic executors only."""
|
||||
execution = prepare_cdsl_execution(cdsl)
|
||||
if strict:
|
||||
error = _preflight_error(execution.analysis)
|
||||
if error is not None:
|
||||
raise error
|
||||
execution.execute_all(strict=strict)
|
||||
return finalize_cdsl_execution(execution, out_step)
|
||||
|
||||
Reference in New Issue
Block a user